Data preparation script for Sierra Nevada time series analysis

# 1. Read in isotope data from various sources
# First load helper functions 'read_jena_ams_results.R', 'read_jena_iso_results.R' 
source("./utilities/jena_ams_ingest.R")
source("./utilities/jena_iso_ingest.R")
source("./utilities/jena_elm_ingest.R")
# Create template for bulk soil data
template19.fx <- function(pm, eco, ndepth) {
  df <- data.frame(Year = rep(2019, ndepth * 3),
                   PM = rep(pm, ndepth * 3),
                   ECO = rep(eco, ndepth * 3),
                   pro_rep = rep(seq(1,3), each = ndepth),
                   lyr_top = rep(seq(0, (ndepth-1) * 10, by = 10), 3),
                   lyr_bot = rep(seq(10, (ndepth) * 10, by = 10), 3))
  df$pro_name <- paste0(df$PM, df$ECO, "_", df$pro_rep)
  df$lyr_name <- paste0(df$pro_name, "_", df$lyr_top, "-", df$lyr_bot)
  return(df)
}

# Create template for composite soil data (incubations, density fractions, etc.)
template.comp.fx <- function(year, pm, eco, depth_bot = c(10, 20, 30), dat) {
  ndepth <- length(depth_bot)
  df <- data.frame(Year = rep(year, ndepth * length(pm)),
                   PM = rep(pm, each = ndepth * length(eco)),
                   ECO = rep(eco, each = ndepth))
  df$lyr_bot <- depth_bot
  df$lyr_top <- sapply(seq_along(depth_bot), function(i) {
    if (i == 1) {
      depth_top <- 0
      } else {
        depth_top <- depth_bot[i - 1]
      }
  })
  df$pro_name <- paste0(df$PM, df$ECO, "_comp")
  n <- nrow(df)
  if (dat == "inc") {
    df <- rbind(df, df)
    df$rep <- rep(c("a", "b"), each = n)
    df$lyr_name <- paste0(df$pro_name, "_", 
                          df$lyr_top, "-", 
                          df$lyr_bot, "_", 
                          df$Year, "_",
                          df$rep)
  } else if (dat == "density") {
    df <- rbind(df, df, df)
    df$frc <- rep(c("fLF", "oLF", "mnC"), each = n)
    df$lyr_name <- paste0(df$pro_name, "_", 
                          df$lyr_top, "-", 
                          df$lyr_bot, "_", 
                          df$Year, "_",
                          df$frc)
  }
  return(df)
}

# templates for bulk soil data
# GRrf 
GRrf <- template19.fx("GR", "rf", 7)
GRrf <- if(any(GRrf$lyr_name == "GRrf_1_60_70")) {
  GRrf <- GRrf[-which(GRrf$lyr_name == "GRrf_1_60_70"), ] # NB: GRrf_1_60_70 doesn't exist
} else {
  GRrf <- GRrf
}
# GRwf
GRwf <- template19.fx("GR", "wf", 9)
# GRpp
GRpp <- template19.fx("GR", "pp", 8)

# ANrf 
ANrf <- template19.fx("AN", "rf", 6)
# ANwf
ANwf <- template19.fx("AN", "wf", 6)
# ANpp
ANpp <- template19.fx("AN", "pp", 8)

# BSrf 
BSrf <- template19.fx("BS", "rf", 8)
BSrf <- if(any(BSrf$lyr_name == "GRrf_1_60_70")) {
  BSrf <- BSrf[-which(BSrf$lyr_name == "BSrf_1_70_80"), ] # NB: BSrf_1_70_80 doesn't exist
} else {
  BSrf <- BSrf
} 
# BSwf
BSwf <- template19.fx("BS", "wf", 7)
# BSpp
BSpp <- template19.fx("BS", "pp", 8)
BSpp[BSpp$lyr_bot == 80, "lyr_bot"] <- 75 # only sampled to 75cm, not 80

sra.2019.df <- rbind(GRrf, GRwf, GRpp,
                     ANrf, ANwf, ANpp,
                     BSrf, BSwf, BSpp)

# template for 2019 incubation data
sra.2019.inc.df <- template.comp.fx(2019, 
                                    pm = c("AN", "BS", "GR"),
                                    eco = c("pp", "wf", "rf"),
                                    dat = "inc")

## template for 2001 incubation data
# list of depths for 2001 inc samples
depth_bot_2001.ls <- list(ANpp = c(6, 13, 33),
                          ANwf = c(11, 35),
                          ANrf = c(11, 32),
                          BSpp = c(7, 18, 28),
                          BSwf = c(10, 19),
                          BSrf = c(8, 15, 30),
                          GRpp = c(7, 15, 27),
                          GRwf = c(4, 13, 28),
                          GRrf = c(8, 27)) 
# template for inputs to template.comp.fx (year, pm, eco)
inc.2001.template <- lapply(seq_along(depth_bot_2001.ls), function(i) {
  nms <- names(depth_bot_2001.ls)
  ls <- list(year = 2001, 
             pm = substr(nms[i], 1, 2), 
             eco = substr(nms[i], 3, 4))
  ls$depth_bot <- depth_bot_2001.ls[[i]]
  return(ls)
})
# create template data frame by iteratively calling template.comp.fx
sra.2001.inc.df <- bind_rows(
  lapply(seq_along(inc.2001.template), function(i) {
    template.comp.fx(year = inc.2001.template[[i]][[1]],
                     pm = inc.2001.template[[i]][[2]],
                     eco = inc.2001.template[[i]][[3]],
                     depth_bot = inc.2001.template[[i]][[4]],
                     dat = "inc")
  })
)

# 2001 bulk soil template
sra.2001 <- vector(mode = "list", length = length(unique(sra.2019.df$pro_name)))
names(sra.2001) <- unique(sra.2019.df$pro_name)

# 2019 bulk soil template
sra.2019 <- sra.2001

# inc templates for merging 14C data
sra.2019.inc <- vector(mode = "list", length = length(unique(sra.2019.inc.df$pro_name)))
names(sra.2019.inc) <- unique(sra.2019.inc.df$pro_name)
sra.2001.inc <- sra.2019.inc
# copies for reps of incubations
sra.2019.inc_L <- sra.2019.inc
names(sra.2019.inc_L) <- substr(names(sra.2019.inc_L), 1, 4)
# complete cases, convert type for calculating stocks later
# could calculate stocks now and then remove for the following steps where not needed

## 2001 summary data
soc.2001 <- data.frame(read_excel("../data/external/sra_ras_sum/sierra_data_summary_2020.xlsx",
                                  sheet = "2001_bulk_data"))

# create list; remove BS samples deeper than 30 cm
soc.2001.ls <- lapply(split(soc.2001, soc.2001$PMeco), function(df) {
  df <- type.convert(df[complete.cases(df), c("ID", "C.", "bd.g.cm3", "PMeco", "pro_rep", "lyr_top", "lyr_bot")])
 return(df[which(df$lyr_bot < 36), ])
})

# Incubation samples combined 0-3 and 3-8 depth increments for BSrf and GRrf
# combine BSrf and GRrf initial depths
# function for calculating weighted average of first two depth increment C content
d1d2.fx <- function(df) {
  d1d2 <- data.frame(ID = paste(df$PMeco[1], df$pro_rep[1], df$lyr_top[1], df$lyr_bot[2], sep = "_"),
                     C. = sum(df$C.[1] * ((df$lyr_bot[1] - df$lyr_top[1]) / df$lyr_bot[2]), df$C.[2] * ((df$lyr_bot[2] - df$lyr_top[2]) / df$lyr_bot[2])),
                     bd.g.cm3 = df$bd.g.cm3[1],
                     PMeco = df$PMeco[1],
                     pro_rep = df$pro_rep[1],
                     lyr_top = df$lyr_top[1],
                     lyr_bot = df$lyr_bot[2])
  return(rbind(d1d2,
               df[3:nrow(df), ]))
}
# Run d1d2.fx for BSrf, GRrf
soc.2001.ls.inc <- soc.2001.ls 
soc.2001.ls.inc$GRrf <- bind_rows(lapply(split(soc.2001.ls$GRrf, soc.2001.ls$GRrf$pro_rep), d1d2.fx))
soc.2001.ls.inc$BSrf <- bind_rows(lapply(split(soc.2001.ls$BSrf, soc.2001.ls$BSrf$pro_rep), d1d2.fx))

# calculate SOC stocks
soc.2001.ls <- lapply(soc.2001.ls, function(df) {
  df$lyr_soc_kgm2 <- df$C. * df$bd.g.cm3 * (df$lyr_bot - df$lyr_top) * 10^-1
  return(df)
})

# summarize [note that soc stocks are dropped]
soc.2001.sum <- data.frame(bind_rows(lapply(soc.2001.ls, function(df) {
  df %>%
    mutate(ID2 = paste0(PMeco, "_", lyr_top, "-", lyr_bot)) %>%
    group_by(ID2, bd.g.cm3, PMeco, lyr_top, lyr_bot) %>%
    summarize(c_pct_avg = mean(C.))
})))

# 2019 data
sra.2019.cn.sum <- data.frame(
  bind_rows(unlist(elm_results_ls, recursive = FALSE)) %>%
  mutate(PMeco = sapply(strsplit(ID, "_"), "[", 2),
         depth = sapply(strsplit(ID, "_"), "[", 4)) %>%
  group_by(PMeco, depth) %>%
  summarize(c_pct_avg = mean(C)))
sra.2019.cn.sum$ID2 <- paste(sra.2019.cn.sum$PMeco, sra.2019.cn.sum$depth, sep = "_")
## read in timeseries of CO2 release from incubations
# 2019
sra.19a.co2.ts <- read.csv("../data/derived/lab_jena_CO2-timeseries/S19a_CO2_flux_2021-01-19.csv")
sra.19b.co2.ts <- read.csv("../data/derived/lab_jena_CO2-timeseries/S19b_CO2_flux_2021-01-19.csv")

# 2001
sra.01.1.co2.ts <- read.csv("../data/derived/lab_jena_CO2-timeseries/S01_1_CO2_flux_2021-01-27.csv")
sra.01.2.co2.ts <- read.csv("../data/derived/lab_jena_CO2-timeseries/S01_2_CO2_flux_2021-01-27.csv")

## Test that required names are present
nms <- c("PMeco", "ID", "dw_g", "timepoint_cmtv",  "time_d", "mgCO2_jar")
invisible(lapply(list(sra.19a.co2.ts,
                      sra.19b.co2.ts,
                      sra.01.1.co2.ts,
                      sra.01.2.co2.ts),
       function(x) {
         ifelse(!is.na(match(nms, names(x))), "yes", "no")
       }
       ))

# combine all data, remove time points without CO2 measurements, and add year and rep 
ts <- bind_rows(sra.19a.co2.ts[ , nms], 
                sra.19b.co2.ts[ , nms], 
                sra.01.1.co2.ts[ , nms],
                sra.01.2.co2.ts[ , nms])
if(length(which(is.na(ts$mgCO2_jar))) > 0) {
  ts <- ts[-which(is.na(ts$mgCO2_jar)), ]
}
ts$year <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 3)
ts$rep <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 4)
ts$depth <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 2)
ts$ID2 <- paste(ts$PMeco, ts$depth, sep = "_")

# add C content
ts[which(ts$year == 2001), "gC_gS"] <- soc.2001.sum[match(ts[which(ts$year == 2001), "ID2"], soc.2001.sum$ID2), "c_pct_avg"] * 10^-2
ts[which(ts$year == 2019), "gC_gS"] <- sra.2019.cn.sum[match(ts[which(ts$year == 2019), "ID2"], sra.2019.cn.sum$ID2), "c_pct_avg"] * 10^-2

# calculate per unit carbon fluxes
ts$mgCO2_gC <- ts$gC_gS * ts$dw_g * ts$mgCO2_jar * (12/44)
ts$mgCO2_gC_d <- ts$mgCO2_gC / ts$time_d

# average reps
ts.avg <- ts %>%
  group_by(PMeco, year, depth, timepoint_cmtv) %>%
  summarize(time_d = mean(time_d),
            mgCO2_gC_d_avg = mean(mgCO2_gC_d),
            mgCO2_gC_d_max = max(mgCO2_gC_d),
            mgCO2_gC_d_min = min(mgCO2_gC_d),
            mgCO2_gC_avg = mean(mgCO2_gC),
            mgCO2_gC_max = max(mgCO2_gC),
            mgCO2_gC_min = min(mgCO2_gC)) %>%
  mutate(PMeco_depth_year = paste(PMeco, depth, year, sep = "_"))

# add depth index
t1 <- ts.avg[ts.avg$timepoint_cmtv == 1, ]
t1 <- data.frame(
  bind_rows(
    lapply(split(t1, t1$year), function(df) {
      bind_rows(lapply(split(df, df$PMeco), function(x) {
        x$lyr_top <- as.numeric(sapply(strsplit(x$depth, "-"), "[", 1))
        x <- x[order(x$lyr_top), ]
        x$depth_index <- seq(1, nrow(x))
        return(x)
      }))
    })))
ts.avg$depth_index <- t1[match(ts.avg$PMeco_depth_year, t1$PMeco_depth_year), "depth_index"]
fig.n <- 1
# function for plotting
ts.plot.fx <- function(df, yr, increment, cumulative = TRUE) {
      if (cumulative) {
        df %>%
          filter(year == yr & depth_index == increment) %>%
          mutate(PM = ifelse(grepl("AN", PMeco), "AN",
                             ifelse(grepl("BS", PMeco), "BS", "GR")),
                 eco = factor(ifelse(grepl("rf", PMeco), "rf", 
                                     ifelse(grepl("wf", PMeco), "wf", "pp")),
                              levels = c("pp", "wf", "rf"))) %>%
          ggplot(., aes(time_d, mgCO2_gC_avg, color = PM, shape = eco)) +
          geom_ribbon(aes(ymin = mgCO2_gC_max, ymax = mgCO2_gC_min, fill = PM, linetype = eco, alpha = 0.2), show.legend = FALSE) +
          geom_point(aes(time_d, mgCO2_gC_max, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_point(aes(time_d, mgCO2_gC_min, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_line(aes(color = PM, linetype = eco), size = 1.2) +
          facet_grid(rows = vars(eco),
                     labeller = labeller(eco = c("rf" = "cold", "wf" = "cool", "pp" = "warm"))) +
          scale_x_continuous(limits = c(0,30)) +
          scale_color_manual(name = "Parent material",
                             labels = c("AN" = "andesite",
                                        "BS" = "basalt",
                                        "GR" = "granite"),
                             values = c("AN" = "blue", 
                                        "BS" = "red", 
                                        "GR" = "darkgray")) +
          scale_shape_manual(name = "Climate",
                             labels = c("rf" = "cold",
                                        "wf" = "cool",
                                        "pp" = "warm"),
                             values = c("pp" = 21, 
                                        "rf" = 22, 
                                        "wf" = 24)) +
          scale_fill_manual(values =c("AN" = "blue",
                                      "BS" = "red",
                                      "GR" = "darkgray")) +
          scale_linetype_manual(name = "Climate",
                                values = c("rf" = "dotted",
                                           "wf" = "dashed",
                                           "pp" = "solid"),
                                labels = c("rf" = "cold",
                                        "wf" = "cool",
                                        "pp" = "warm")) +
          ylab(expression('Cumulative flux (mgCO'[2]*'-C gC'^-1*')')) +
          xlab("Time (days)") +
          guides(color = guide_legend(order = 1),
                 shape = guide_legend(order = 3)) +
          ggtitle(paste("Cumulative flux, ", yr, "depth ", increment)) +
          theme_bw() +
          theme(panel.grid = element_blank())
    } else {
       df %>%
        filter(year == yr & depth_index == increment) %>%
        mutate(PM = ifelse(grepl("AN", PMeco), "AN",
                           ifelse(grepl("BS", PMeco), "BS", "GR")),
              eco = factor(ifelse(grepl("rf", PMeco), "rf",
                                  ifelse(grepl("wf", PMeco), "wf", "pp")),
                           levels = c("pp", "wf", "rf"))) %>%
        ggplot(., aes(time_d, mgCO2_gC_d_avg, color = PM, shape = eco)) +
        geom_ribbon(aes(ymin = mgCO2_gC_d_max, ymax = mgCO2_gC_d_min, fill = PM, linetype = eco, alpha = 0.2), show.legend = FALSE) +
          geom_point(aes(time_d, mgCO2_gC_d_max, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_point(aes(time_d, mgCO2_gC_d_min, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
        geom_line(aes(color = PM, linetype = eco), size = 1.2) +
        facet_grid(rows = vars(eco),
                   labeller = labeller(eco = c("rf" = "cold", "wf" = "cool", "pp" = "warm"))) +
        scale_x_continuous(limits = c(0,30)) +
        scale_color_manual(name = "Parent material",
                           labels = c("AN" = "andesite",
                                      "BS" = "basalt",
                                      "GR" = "granite"),
                           values = c("AN" = "blue", 
                                      "BS" = "red", 
                                      "GR" = "darkgray")) +
        scale_shape_manual(name = "Climate",
                           labels = c("rf" = "cold",
                                      "wf" = "cool",
                                      "pp" = "warm"),
                           values = c("pp" = 21, 
                                      "rf" = 22, 
                                      "wf" = 24)) +
        scale_fill_manual(values =c("AN" = "blue",
                                    "BS" = "red",
                                    "GR" = "darkgray")) +
        scale_linetype_manual(name = "Climate",
                              values = c("rf" = "dotted",
                                         "wf" = "dashed",
                                         "pp" = "solid"),
                              labels = c("rf" = "cold",
                                      "wf" = "cool",
                                      "pp" = "warm")) +
        ylab(expression('Respiration Rate (mgCO'[2]*'-C gC'^-1*'d'^-1*')')) +
        xlab("Time (days)") +
        guides(color = guide_legend(order = 1),
               shape = guide_legend(order = 3)) +
        ggtitle(paste("Flux rate", yr, "depth ", increment)) +
        theme_bw() +
        theme(panel.grid = element_blank())
    }
}

## cumulative flux
# 2019
ts.plot.fx(ts.avg, yr = "2019", increment = "1")

ts.plot.fx(ts.avg, yr = "2019", increment = "2")

ts.plot.fx(ts.avg, yr = "2019", increment = "3")

# 2001
ts.plot.fx(ts.avg, yr = "2001", increment = "1")

ts.plot.fx(ts.avg, yr = "2001", increment = "2")

ts.plot.fx(ts.avg, yr = "2001", increment = "3")


## flux rates
# 2019
ts.plot.fx(ts.avg, yr = "2019", increment = "1", cumulative = FALSE)

ts.plot.fx(ts.avg, yr = "2019", increment = "2", cumulative = FALSE)

ts.plot.fx(ts.avg, yr = "2019", increment = "3", cumulative = FALSE)

# 2001
ts.plot.fx(ts.avg, yr = "2001", increment = "1", cumulative = FALSE)

ts.plot.fx(ts.avg, yr = "2001", increment = "2", cumulative = FALSE)

ts.plot.fx(ts.avg, yr = "2001", increment = "3", cumulative = FALSE)

Fig. 7. Respiration data from incubations of 2019 and 2001 bulk soils.

Caption: Points show measured CO2 production of laboratory duplicates as cumulative fluxes or daily flux rates by depth, lines show the means, and the ribbon represents the range.

Merge templates with 14C, C, and N data

Radiocarbon analyses for the 2001 samples were not run originally, but were completed on archived samples in 2020.

# Extract 14C data for 2001 samples
ams_results_ls_S01 <- ams_results_ls[grep("S01", names(ams_results_ls))]
for(i in seq_along(sra.2001)) {
  sra.2001[[i]] <- lapply(ams_results_ls_S01, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2001)[i], df$Probe))) {
       df[grep(names(sra.2001)[i], df$Probe), ] 
      }
    })
  })
  sra.2001[[i]] <- Filter(Negate(is.null), unlist(sra.2001[[i]], recursive = FALSE))
}
sra.2001 <- bind_rows(unlist(sra.2001, recursive = FALSE))

# create ID field, trim df, and add depths
sra.2001$ID <- unlist(strsplit(sra.2001$Probe, "_Sierra Nevada_2001"))
sra.2001 <- sra.2001[ , c("ID", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2001) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2001$lyr_top <- as.numeric(ifelse(substr(sra.2001$ID, 9, 9) == "-",
                                      substr(sra.2001$ID, 8, 8),
                                      substr(sra.2001$ID, 8, 9)))
sra.2001$lyr_bot <- as.numeric(ifelse(substr(sra.2001$ID, 9, 9) == "-", 
                                      substr(sra.2001$ID, 10, nchar(sra.2001$ID)),
                                      substr(sra.2001$ID, 11, nchar(sra.2001$ID))))
sra.2001$pro_rep <- substr(sra.2001$ID, 6, 6)
sra.2001$PM <- factor(substr(sra.2001$ID, 1, 2))
sra.2001$ECO <- factor(substr(sra.2001$ID, 3, 4), levels = c("pp", "wf", "rf"))
sra.2001$pro_name <- substr(sra.2001$ID, 1, 6)
sra.2001$PMeco <- substr(sra.2001$ID, 1, 4)

# remove outlier ANpp sample
sra.2001 <- sra.2001[-which(sra.2001$ID == "ANpp_3_6-13"), ]

# make list by PMeco
sra.2001.ls <- split(sra.2001, sra.2001$PMeco)
# Extract 14C data for 2019 samples
ams_results_ls_S19 <- ams_results_ls[grep("soil-S19", names(ams_results_ls))]
for(i in seq_along(sra.2019)) {
  sra.2019[[i]] <- lapply(ams_results_ls_S19, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2019)[i], df$Probe))) {
       df[grep(names(sra.2019)[i], df$Probe), ] 
      }
    })
  })
  sra.2019[[i]] <- Filter(Negate(is.null), unlist(sra.2019[[i]], recursive = FALSE))
}
sra.2019 <- bind_rows(unlist(sra.2019, recursive = FALSE))

## merge w/ 2019 template
# rename cols in AMS tables
sra.2019 <- sra.2019[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
# merge
sra.2019.ls <- lapply(split(sra.2019.df, sra.2019.df$lyr_name), function(df) {
  df <- merge(df, sra.2019[grep(df$lyr_name, sra.2019$ID), ])
  df$ID <- NULL
  df$PMeco <- paste0(df$PM, df$ECO)
  return(df)
})

# reshape list by PMeco
sra.2019.ls <- split(bind_rows(sra.2019.ls), bind_rows(sra.2019.ls)[["PMeco"]])
### Extract 14C data for incubation samples
## respired CO2, soil
# 2019
ams_results_ls_co2_S19 <- ams_results_ls[grep("co2-S19", names(ams_results_ls))]
for (i in seq_along(sra.2019.inc)) {
  sra.2019.inc[[i]] <- lapply(ams_results_ls_co2_S19, function(ls) {
    lapply(ls, function(df) {
      if (any(grepl(names(sra.2019.inc)[i], df$Probe))) {
        df[grep(names(sra.2019.inc)[i], df$Probe), ] 
      }
    })
  })
  sra.2019.inc[[i]] <- Filter(Negate(is.null), unlist(sra.2019.inc[[i]], recursive = FALSE))
}
sra.2019.inc <- type.convert(
  bind_rows(
    lapply(unlist(sra.2019.inc, recursive = FALSE), 
           function(x) x %>% mutate_all(as.character))),
  as.is = TRUE)
sra.2019.inc <- sra.2019.inc[-which(is.na(sra.2019.inc$F14C)), ]

# 2001
ams_results_ls_co2_S01 <- ams_results_ls[grep("co2-S01", names(ams_results_ls))]
# remove questionable/duplicate samples
# ANrf_comp_11-32_2001_a (analyzed twice; both anomously low compared to rep and rest of data)
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx`[-grep("ANrf_comp_11-32_2001_a", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx`$Probe), ]
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx`[-grep("ANrf_comp_11-32_2001_a", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx`$Probe), ]
# from original analysis of samples extracted online 11-Dec-2020 (see readme for notes)
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_23.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_23.xlsx`[-grep("GRwf_comp_13-28_2001_a_11", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe), ]
# from reanalysis of samples extracted online 11-Dec-2020 (see readme for notes)
# GRrf_comp_8-27_2001_a_5, GRrf_comp_8-27_2001_b_6, GRpp_comp_15-27_2001_b_18 
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`[c(
  grep("GRrf_comp_8-27_2001_a_5", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe),
  grep("GRwf_comp_13-28_2001_b_12", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe)), ]

# create template for extracting data
sra.2001.inc <- vector(mode = "list", length = length(unique(sra.2019.inc.df$pro_name)))
names(sra.2001.inc) <- unique(sra.2019.inc.df$pro_name)
# merge with 14C data
for (i in seq_along(sra.2001.inc)) {
  sra.2001.inc[[i]] <- lapply(ams_results_ls_co2_S01, function(ls) {
    lapply(ls, function(df) {
      if (any(grepl(names(sra.2001.inc)[i], df$Probe))) {
        df[grep(names(sra.2001.inc)[i], df$Probe), ] 
      }
    })
  })
  sra.2001.inc[[i]] <- Filter(Negate(is.null), unlist(sra.2001.inc[[i]], recursive = FALSE))
}
sra.2001.inc <- type.convert(
  bind_rows(
    lapply(unlist(sra.2001.inc, recursive = FALSE), 
           function(x) x %>% mutate_all(as.character))),
  as.is = TRUE)
sra.2001.inc <- sra.2001.inc[-which(is.na(sra.2001.inc$F14C)), ]

# respired CO2, litter
ams_results_ls_co2_L19 <- ams_results_ls[grep("co2-L19", names(ams_results_ls))]
for(i in seq_along(sra.2019.inc_L)) {
  sra.2019.inc_L[[i]] <- lapply(ams_results_ls_co2_L19, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2019.inc_L)[i], df$Probe))) {
       df[grep(names(sra.2019.inc_L)[i], df$Probe), ] 
      }
    })
  })
  sra.2019.inc_L[[i]] <- Filter(Negate(is.null), unlist(sra.2019.inc_L[[i]], recursive = FALSE))
}
sra.2019.inc_L <- bind_rows(unlist(sra.2019.inc_L, recursive = FALSE))

## merge w/ templates [why do I do this twice?]
# rename cols in AMS tables
# soil CO2
sra.2019.inc <- sra.2019.inc[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019.inc) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2001.inc <- sra.2001.inc[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2001.inc) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
# merge
# 2019
sra.2019.inc.ls <- bind_rows(
  lapply(split(sra.2019.inc.df, sra.2019.inc.df$lyr_name), function(df) {
    df <- merge(df, sra.2019.inc[grep(df$lyr_name, sra.2019.inc$ID), ])
    df$ID <- NULL
    df$PMeco <- paste0(df$PM, df$ECO)
    return(df)
  })
)
sra.2019.inc.ls <- split(sra.2019.inc.ls, sra.2019.inc.ls$PMeco)
# 2001
sra.2001.inc.ls <- bind_rows(
  lapply(split(sra.2001.inc.df, sra.2001.inc.df$lyr_name), function(df) {
    df <- merge(df, sra.2001.inc[grep(df$lyr_name, sra.2001.inc$ID), ])
    df$ID <- NULL
    df$PMeco <- paste0(df$PM, df$ECO)
    return(df)
  })
)
sra.2001.inc.ls <- split(sra.2001.inc.ls, sra.2001.inc.ls$PMeco)


# litter CO2
sra.2019.inc_L <- sra.2019.inc_L[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019.inc_L) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2019.inc_L$ID <- substr(substring(sra.2019.inc_L$ID, 
                                      regexpr("_", sra.2019.inc_L$ID) + 1, 
                                      nchar(sra.2019.inc_L$ID)),
                            1, 8)
sra.2019.inc.df_L <- data.frame(Year = rep(2019, 18),
                                rep = rep(c(1, 2), 9),
                                PM = rep(c("AN", "BS", "GR"), each = 6),
                                eco = rep(c("pp", "wf", "rf"), each = 2, times = 3))
sra.2019.inc.df_L$PMeco <- paste0(sra.2019.inc.df_L$PM, sra.2019.inc.df_L$eco)
sra.2019.inc.df_L$ID <- paste0(sra.2019.inc.df_L$PM, sra.2019.inc.df_L$eco, "-L_", sra.2019.inc.df_L$rep)
# add dry wts and litter depth
sra.2019.L <- read.csv("../data/derived/lab_jena_litter/Litter_2019_2021-01-27.csv")
sra.2019.inc.df_L <- merge(sra.2019.inc.df_L, sra.2019.L[ , c("PMeco", "lyr_top", "lyr_bot")], all.x = TRUE)
# merge
sra.2019.inc_L.df <- bind_rows(
  lapply(split(sra.2019.inc_L, sra.2019.inc_L$ID), function(df) {
    df <- merge(df, sra.2019.inc.df_L, by = "ID")
    df$ID <- NULL
    return(df)
  })
)
sra.2019.inc_L.ls <- split(sra.2019.inc_L.df, sra.2019.inc_L.df$PMeco)
# fm and d14c conversion functions
lambda <- 1/8267 # = 1/(true mean life of 14C)
calc_fm <- function(d14c, obs_date_y) {
  ((d14c/1000) + 1)/exp(lambda * (1950 - obs_date_y))
}
calc_14c <- function(fm, obs_date_y) {
  (fm * exp(lambda * (1950 - obs_date_y)) - 1) * 1000
}

# calc atm in 2001, 2009, 2019
Datm <- rbind(graven, future14C)
atm.d14.2001 <- Datm[Datm$Date == 2001.5, "NHc14"]
atm.fm.2001 <- calc_fm(atm.d14.2001, 2001)
atm.d14.2009 <- Datm[Datm$Date == 2009.5, "NHc14"]
atm.fm.2009 <- calc_fm(atm.d14.2009, 2009)
atm.d14.2019 <- Datm[Datm$Date == 2019.5, "NHc14"]
atm.fm.2019 <- calc_fm(atm.d14.2019, 2019)
fig.n <- fig.n + 1
# summarize litter inc data
sra.2019.inc_L.sum <- sra.2019.inc_L.df %>%
  mutate(eco = factor(ifelse(eco == "pp", "warm",
                             ifelse(eco == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = factor(ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))),
         Year = factor("2019")) %>%
  group_by(Year, pm, eco, lyr_top, lyr_bot) %>%
  summarize(d14c_mean = mean(d14c),
            d14c_u = max(d14c),
            d14c_l = min(d14c))

# plot as cols by climate
sra.2019.inc_L.sum %>%
  mutate(MAT = factor(eco, levels = c("warm", "cool", "cold"), labels = c("10-13", "8-10", "5-6"))) %>%
  ggplot(., aes(MAT, d14c_mean, fill = pm)) +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
  geom_col(position = "dodge2") +
  geom_errorbar(aes(ymax = d14c_u, ymin = d14c_l, color = pm), 
                position = position_dodge2(width = .5, padding = .5)) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue", 
                               "basalt" = "red", 
                               "granite" = "darkgray")) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  coord_flip() +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab(expression("MAT ("*~degree*C*")")) +
  theme_bw() +
  theme(panel.grid = element_blank())


# plot as points with depth
sra.2019.inc_L.sum %>%
  ggplot(., aes(d14c_mean, lyr_top, color = pm)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_point(size = 3) +
  geom_errorbarh(aes(xmax = d14c_u, xmin = d14c_l), height = 1) +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  facet_grid(rows = vars(eco)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid = element_blank())

Fig. 7. Litter incubation \(\Delta\)14C-CO2 (2019)

Caption: Mean \(\Delta\)14C-CO2 for each site. Error bars show min and max of duplicate incubation samples. a) Data shown by site, without litter depth, b) Data shown by depth of litter layer, binned by climate zone.

pro.plot <- function(df, maxDepth, min14C, rep) {
  ggplot(df, aes(d14c, lyr_bot, color = PM, shape = ECO, group = rep)) +
    geom_vline(xintercept = 0) +
    geom_hline(yintercept = 0) +
    geom_point(size = 3) +
    geom_path() +
    scale_y_reverse(limits = c(maxDepth, 0)) +
    scale_x_continuous(limits = c(min14C, 180)) +
    scale_color_manual(name = "parent material",
                       labels = c("AN" = "andesite",
                                  "BS" = "basalt",
                                  "GR" = "granite"),
                       values = c("AN" = "blue", 
                                  "BS" = "red", 
                                  "GR" = "darkgray")) +
    scale_shape_manual(name = "ecosystem",
                       labels = c("pp" = expression(italic("P. ponderosa")),
                                  "rf" = expression(italic("A. magnifica")),
                                  "wf" = expression(italic("A. concolor"))),
                       values = c("pp" = 15, 
                                  "rf" = 16, 
                                  "wf" = 17)) +
    xlab(expression(Delta*''^14*'C (‰)')) +
    ylab("Depth (cm)") +
    theme_bw() +
    theme(panel.grid.minor = element_blank())
}
# lapply(sra.2001.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), df$pro_rep))
# lapply(sra.2019.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), df$pro_rep))
# lapply(sra.2019.inc.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), NA))

2001 mean radiocarbon profiles

# combine reps
sra.2001.sum.ls  <- lapply(sra.2001.ls, function(df) {
  df <- data.frame(df %>%
                     filter(lyr_bot <= 40) %>%
                     mutate(lyr_top_ch = as.character(lyr_top),
                            lyr_bot_ch = as.character(lyr_bot)) %>%
                     select(PM, ECO, PMeco, fm, d14c, lyr_top_ch, lyr_bot_ch) %>%
                     group_by(PM, ECO, PMeco, lyr_top_ch, lyr_bot_ch) %>%
                     summarize_all(list(mean = mean, sd = sd), na.rm = TRUE))
  names(df) <- c("PM", "ECO", "PMeco", "lyr_top", "lyr_bot", "fm", "d14c", "fm_sd", "d14c_sd")
  df$lyr_top <- as.numeric(df$lyr_top)
  df$lyr_bot <- as.numeric(df$lyr_bot)
  df$d14c_u <- df$d14c + df$d14c_sd
  df$d14c_l <- df$d14c - df$d14c_sd
  return(df[order(df$lyr_bot), ])
})
sra.01.sum <- bind_rows(sra.2001.sum.ls) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")))

# plot
fig.n <- fig.n + 1
sra.01.sum %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse(limits = c(40, 0)) +
  scale_x_continuous(limits = c(-100, 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Mean profile \(\Delta\)14C for 2001 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2001. Error bars show ±1 standard deviation, solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling.

2009 radiocarbon profiles

# 2009 data (from C. Rasmussen)
ras18.lyr <- read.csv("/Users/jeff/R/14Constraint/ras_2018.csv")
ras18.lyr$ECO <- factor(ras18.lyr$MAST, labels = c("rf","wf","pp"))
# add PMeco col
ras18.lyr$ECO <- factor(ras18.lyr$MAST, labels = c("rf","wf","pp"))
ras18.lyr$PMeco <- paste0(ras18.lyr$PM, ras18.lyr$ECO)

# summarize 09 data
sra.09.sum <- ras18.lyr %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")))

fig.n <- fig.n + 1
sra.09.sum %>%
  ggplot(., aes(lyr_14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2009) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_path(linetype = "dashed") +
  scale_y_reverse() +
  scale_x_continuous(limits = c(-100, 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 0, 
                                "cool" = 1, 
                                "cold" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Profile \(\Delta\)14C for 2009 samples

Caption: Profile \(\Delta\)14C by depth for each site in 2009. Solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling. Error bars not shown as only a single replicate profile was analyzed per site.

2019 mean radiocarbon profiles

# combine reps
sra.2019.sum.ls  <- lapply(sra.2019.ls, function(df) {
  df <- data.frame(df %>%
                     mutate(lyr_top_ch = as.character(lyr_top),
                            lyr_bot_ch = as.character(lyr_bot)) %>%
                     select(PM, ECO, PMeco, fm, d14c, lyr_top_ch, lyr_bot_ch) %>%
                     group_by(PM, ECO, PMeco, lyr_top_ch, lyr_bot_ch) %>%
                     summarize_all(list(mean = mean, sd = sd), na.rm = TRUE))
  names(df) <- c("PM", "ECO", "PMeco", "lyr_top", "lyr_bot", "fm", "d14c", "fm_sd", "d14c_sd")
  df$lyr_top <- as.numeric(df$lyr_top)
  df$lyr_bot <- as.numeric(df$lyr_bot)
  df$d14c_u <- df$d14c + df$d14c_sd
  df$d14c_l <- df$d14c - df$d14c_sd
  return(df)
})
sra.19.sum <- bind_rows(sra.2019.sum.ls) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) 

# plot
fig.n <- fig.n + 1
sra.19.sum %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2019) +
  geom_hline(yintercept = 0) +
  geom_point(size = 2.7) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse(limits = c(max(sra.19.sum$lyr_bot), 0)) +
  scale_x_continuous(limits = c(min(sra.19.sum$d14c), 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Mean profile \(\Delta\)14C for 2019 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2019. Error bars show ±1 standard deviation, solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling.

Change in \(\Delta\)14C over time between 2001 and 2019

# combine '01 and '19 data for plotting
sra.01.sum$Year <- 2001
sra.19.sum$Year <- 2019

sra.all <- rbind(sra.01.sum, sra.19.sum)
sra.all$Year <- as.factor(sra.all$Year)

fig.n <- fig.n + 1
sra.all %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         ecoYear = paste0(ECO, Year),
         ecoYear2 = ifelse(ecoYear == "pp2001", "warm (2001)",
                           ifelse(ecoYear == "pp2019", "warm (2019)",
                                  ifelse(ecoYear == "wf2001", "cool (2001)",
                                         ifelse(ecoYear == "wf2019", "cool (2019)",
                                                ifelse(ecoYear == "rf2001", "cold (2001)", "cold (2019)")))))) %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = ecoYear2, group = PMeco_year)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path(aes(linetype = Year)) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Mean profile \(\Delta\)14C for 2001 and 2019 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2001 and 2019. Error bars show ±1 standard deviation. Vertical lines show \(\Delta\)14C of the atmosphere in 2001 (solid) and 2019 (dashed).

Incubation \(\Delta\)14C-CO2

## 2019
sra.2019.inc.df <- bind_rows(sra.2019.inc.ls)
# add litter inc data and summarize
sra.2019.inc.sum.df <- data.frame(rbind(
  sra.2019.inc_L.sum[ , which(names(sra.2019.inc_L.sum) != "lyr_top")],
  sra.2019.inc.df %>%
    mutate(eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
           pm = factor(ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))),
           # remove GRrf 10-20 "a" point
           d14c = replace(d14c, which(d14c < -300), NA),
           Year = factor(Year)) %>%
  group_by(Year, pm, eco, lyr_bot, lyr_top) %>%
  summarize(d14c_mean = mean(d14c, na.rm = TRUE),
            d14c_l = min(d14c, na.rm = TRUE),
            d14c_u = max(d14c, na.rm = TRUE)) %>%
    select(-lyr_top)))

# 2001
sra.2001.inc.df <- bind_rows(sra.2001.inc.ls)
sra.2001.inc.sum.df <- data.frame(
  sra.2001.inc.df %>%
    mutate(eco = factor(ifelse(ECO == "pp", "warm",
                               ifelse(ECO == "wf", "cool", "cold")),
                        levels = c("warm", "cool", "cold")),
           pm = factor(ifelse(PM == "AN", "andesite",
                       ifelse(PM == "BS", "basalt", "granite"))),
           Year = factor(Year)) %>%
    group_by(Year, PMeco, pm, eco, lyr_bot, lyr_top) %>%
    summarize(d14c_mean = mean(d14c),
              d14c_l = min(d14c),
              d14c_u = max(d14c),
              fm_mean = mean(fm),
              fm_l = min(fm),
              fm_u = max(fm))
)
sra.2001.inc.sum.ls <- split(sra.2001.inc.sum.df, sra.2001.inc.sum.df$PMeco)
sra.2001.inc.sum.df <- sra.2001.inc.sum.df[ , !(names(sra.2001.inc.sum.df) %in% c("fm_mean", "fm_l", "fm_u", "lyr_top", "PMeco"))]
# 2019
fig.n <- fig.n + 1
sra.2019.inc.sum.df[order(sra.2019.inc.sum.df$lyr_bot), ] %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = eco)) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm),
    height = 1.5) +
  geom_path(linetype = "dashed") +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 0, 
                                "cool" = 1, 
                                "cold" = 2)) +
  xlab(expression('Incubation '*Delta*''^14*'C-CO'[2]*' (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. \(\Delta\)14C-CO2 of 2019 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2019. One rep from GRrf 10-20 (the 10-20 cm increment sample from the cold granite site) is strongly depleted relative to the other rep: \(\Delta\)14C-CO2 = -210.1. The highly depleted sample has been excluded for display reasons.

# plot 2001 data
fig.n <- fig.n + 1
sra.2001.inc.sum.df %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = eco)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm),
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue",
                                "basalt" = "red",
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15,
                                "cool" = 16,
                                "cold" = 17)) +
  scale_x_continuous(limits = c(-70, 190)) +
  xlab(expression('Incubation '*Delta*''^14*'C-CO'[2]*' (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. \(\Delta\)14C-CO2 of 2001 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2001. Note that some sites only have two depth increments. Similar to the 2019 dataset, one of the GRrf reps from the deepest depth increment was strongly depleted: \(\Delta\)14C-CO2 = -469.1. Both points have been excluded for display reasons.

# plot together
sra.inc.all <- rbind(sra.2001.inc.sum.df, sra.2019.inc.sum.df)

fig.n <- fig.n + 1 
sra.inc.all %>%
  filter(lyr_bot > 0) %>%
  mutate(PMeco_year = paste0(pm, eco, Year),
         ecoYear = paste0(eco, " (", Year, ")")) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ecoYear, group = PMeco_year)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path(aes(linetype = Year)) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_x_continuous(limits = c(-70, 190)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. \(\Delta\)14C-CO2 of 2001 and 2019 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2001 and 2019. Different depth increments were sampled in 2001 and 2019. Points are the mean of laboratory duplicates; error bars are the measured values of each duplicate. Granite/cold point exlcuded for display reasons as it is strongly depleted.

Incubation vs. bulk soil \(\Delta\)14C

# bind rows of inc list
sra.19.inc <- sra.2019.inc.sum.df
sra.19.inc$Type <- "inc"

# 2001
sra.01.inc <- sra.2001.inc.sum.df
sra.01.inc$Type <- "inc"

# rbind bulk data
sra.19.bulk <- sra.19.sum[which(sra.19.sum$lyr_bot < 31), c("Year", "PM", "ECO", "lyr_bot","d14c", "d14c_l", "d14c_u")]
names(sra.19.bulk)[which(names(sra.19.bulk) == "d14c")] <- "d14c_mean"
sra.19.bulk$Type <- "bulk"
sra.19.bulk <- sra.19.bulk %>%
  mutate(pm = factor(ifelse(PM == "AN", "andesite",
                            ifelse(PM == "BS", "basalt", "granite"))),
         eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         PM = NULL,
         ECO = NULL)
sra.19.inc.blk <- rbind(data.frame(sra.19.inc), data.frame(sra.19.bulk))
save(sra.19.inc.blk, file = "sra.19.inc.blk.RData")

# 2001
# Need to calculate weighted average of radiocarbon values and stocks for combined inc depths 
# 1) add SOC stocks to duplicate sra.2001.ls obj
sra.2001.ls2 <- sra.2001.ls
for(i in seq_along(sra.2001.ls2)) {
  ix <- match(sra.2001.ls2[[i]][["ID"]], soc.2001.ls[[i]][["ID"]])
  sra.2001.ls2[[i]]["lyr_soc_kgm2"] <- soc.2001.ls[[i]][ix, "lyr_soc_kgm2"]
}
# 2) weighted average fx
d1d2.14c.fx <- function(df) {
  sum_soc <- sum(df[1:2, "lyr_soc_kgm2"])
  wt1 <- df$lyr_soc_kgm2[1] / sum_soc
  wt2 <- df$lyr_soc_kgm2[2] / sum_soc
  d1d2 <- df[1, ]
  d1d2$ID = paste(df$PMeco[1], df$pro_rep[1], df$lyr_top[1], df$lyr_bot[2], sep = "_")
  d1d2$lyr_soc_kgm2 = sum(df$lyr_soc_kgm2[1], df$lyr_soc_kgm2[2])
  d1d2$lyr_bot = df$lyr_bot[2]
  d1d2$fm <- sum(df$fm[1] * wt1, df$fm[2] * wt2)
  d1d2$d14c <- sum(df$d14c[1] * wt1, df$d14c[2] * wt2)
  return(rbind(d1d2,
               df[3:nrow(df), ]))
}
# 3) calc. wtd. average for GRrf
sra.2001.ls2$GRrf <- bind_rows(
  lapply(split(sra.2001.ls2$GRrf, sra.2001.ls2$GRrf$pro_rep), function(x) {
    d1d2.14c.fx(x)
  })
)
# 4) calc. wtd. average for BSrf
#    - problem here is that only one pro_rep has 0-3 cm data
#    - so, need to calculate weighted SOC, then calculate weighted 14C
#    - composite 0-8 = 15g BSrf_1_0-3 + 5 g from each pro_rep BSrf_3-8
BSrf_comp_01_i <- sra.2001.ls2$BSrf[which(sra.2001.ls$BSrf$lyr_bot < 9), ]
BSrf_comp_01_i$soc_wt <- c(15 / 30, rep(5 / 30, 3))
BSrf_comp_01_i$soc_wtd <- BSrf_comp_01_i$lyr_soc_kgm2 * BSrf_comp_01_i$soc_wt

# create summarized list
sra.2001.sum.ls2  <- lapply(sra.2001.ls2, function(df) {
  data.frame(
    df %>%
      filter(lyr_bot <= 40) %>%
      mutate(lyr_bot_ch = as.character(lyr_bot)) %>%
      select(PMeco, d14c, fm, lyr_bot_ch, lyr_soc_kgm2) %>%
      group_by(PMeco, lyr_bot_ch) %>%
      summarize(
        across(where(is.numeric), list(mean = mean, sd = sd), na.rm = TRUE)) %>%
      mutate(lyr_bot = as.numeric(lyr_bot_ch)) %>%
      select(-lyr_bot_ch)
  )
})

# remove BSrf row w/ lyr_bot = 3
sra.2001.sum.ls2$BSrf <- sra.2001.sum.ls2$BSrf[-which(sra.2001.sum.ls2$BSrf$lyr_bot == 3), ]
# calculate weighted average for d14c, fm, lyr_soc_kgm2
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "d14c_mean"] <- sum(BSrf_comp_01_i$d14c * (BSrf_comp_01_i$soc_wtd / sum(BSrf_comp_01_i$soc_wtd)))
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "fm_mean"] <- sum(BSrf_comp_01_i$fm * (BSrf_comp_01_i$soc_wtd / sum(BSrf_comp_01_i$soc_wtd)))
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "lyr_soc_kgm2_mean"] <- sum(BSrf_comp_01_i$soc_wtd)
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), c("d14c_sd", "fm_sd", "lyr_soc_kgm2_sd")] <- NA

# calculate cmtv soc
sra.2001.sum.ls2 <- lapply(sra.2001.sum.ls2, function(x) {
  x <- x[order(x$lyr_bot), ]
  x$lyr_soc_cmtv <- NA
  for(i in seq_along(x$lyr_bot)) {
      if(i == 1) {
        x$lyr_soc_cmtv[i] <- x$lyr_soc_kgm2_mean[i]
      } else {
        x$lyr_soc_cmtv[i] <- x$lyr_soc_kgm2_mean[i] + x$lyr_soc_cmtv[i-1] 
      }
  }
  return(x)
})

# make df
sra.01.sum <- data.frame(bind_rows(
  lapply(sra.2001.sum.ls2, function(df) {
    df %>%
      mutate(eco = factor(ifelse(grepl("pp", df$PMeco), "warm",
                                 ifelse(grepl("wf", df$PMeco), "cool", "cold")),
                          levels = c("warm", "cool", "cold")),
             pm = ifelse(grepl("AN", df$PMeco), "andesite",
                         ifelse(grepl("BS", df$PMeco), "basalt", "granite")),
             d14c_u = d14c_mean + d14c_sd,
             d14c_l = d14c_mean - d14c_sd,
             Year = 2001,
             Type = "bulk") %>%
      select(names(sra.01.inc)) %>%
      arrange(lyr_bot)
  })
))
# bind with inc
sra.01.inc.blk <- rbind(data.frame(sra.01.inc), sra.01.sum)
save(sra.01.inc.blk, file = "sra.01.inc.blk.RData")
# plot 2019
fig.n <- fig.n + 1
# p <-
sra.19.inc.blk %>%
  mutate(ECOtype = paste0(eco, " (", Type, ")")) %>%
  arrange(lyr_bot) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ECOtype, linetype = Type)) +
  geom_vline(xintercept = atm.d14.2019) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (type)",
                     values = c("warm (bulk)" = 15, 
                                "cool (bulk)" = 16, 
                                "cold (bulk)" = 17,
                                "warm (inc)" = 0, 
                                "cool (inc)" = 1, 
                                "cold (inc)" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# ggsave("sra.bulkInc.19.pdf", p, device = cairo_pdf, width = 9.5, height = 5, units = "in")

Fig. 7. \(\Delta\)14C of 2019 bulk soil incubations and corresponding bulk soil

Caption: \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2019. Error bars show one standard deviation for bulk soil, points show mean of three replicate profiles for bulk soils and single observations for respired CO2.

# plot 2001
fig.n <- fig.n + 1
sra.01.inc.blk %>%
  mutate(ECOtype = paste0(eco, " (", Type, ")")) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ECOtype, linetype = Type)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (type)",
                     values = c("warm (bulk)" = 15, 
                                "cool (bulk)" = 16, 
                                "cold (bulk)" = 17,
                                "warm (inc)" = 0, 
                                "cool (inc)" = 1, 
                                "cold (inc)" = 2)) +
  scale_x_continuous(limits = c(-100, 200)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. \(\Delta\)14C of 2001 bulk soil incubations and corresponding bulk soil

Caption: \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2001. Points show mean of three replicate profiles for bulk soils and mean of laboratory duplicates for respired CO2. The incubated soil samples are a composite made by homogenizing subsamples from each of the three replicate profile samples by depth. Error bars show one standard deviation for bulk soil and the measured values from laboratory duplicates of the incubated composite samples.

# first merge mean 14C data from 2019 samples with composite incubation data
nms.inc.blk <- c("pm", "eco", "lyr_bot", "Year")
sra.19.inc.blk2 <- left_join(sra.19.bulk %>% mutate(., Year = as.factor(Year)),
                             sra.2019.inc.sum.df,
                             by = nms.inc.blk,
                             suffix = c(".bulk", ".inc"))
# 2001
sra.01.inc.blk2 <- left_join(sra.01.sum %>% mutate(., Year = as.factor(Year)),
                             sra.01.inc,
                             by = nms.inc.blk,
                             suffix = c(".bulk", ".inc"))
sra.01.inc.blk2$PMeco <- paste0(sra.01.inc.blk2$pm, sra.01.inc.blk2$eco)
# add depth factor
sra.01.inc.blk2 <- unsplit(
  lapply(split(sra.01.inc.blk2, sra.01.inc.blk2$PMeco), function(x) {
  x$depth <- seq(1, nrow(x))
  return(x) 
  }), 
sra.01.inc.blk2$PMeco)
sra.01.inc.blk2 <- sra.01.inc.blk2[which(sra.01.inc.blk2$lyr_bot < 35), ]
sra.01.inc.blk2$depth <- factor(sra.01.inc.blk2$depth)

# regress bulk vs. inc
min.inc.blk.19 <- min(sra.19.inc.blk2$d14c_l.inc,
                      sra.19.inc.blk2$d14c_l.bulk) # exclude highly negative incubation sample from GRwf
max.inc.blk.19 <- max(sra.19.inc.blk2$d14c_l.inc,
                      sra.19.inc.blk2$d14c_l.bulk)

# What is the ideal grouping/expected relationship?
## look at combinatorial dataset
# sra.all.df.fx <- function(ls, year) {
#   cbind(bind_rows(lapply(ls, function(df) df[ , c("PMeco", "lyr_bot", "d14c")])),
#         year = year)
# }
# sra.all.df <- inner_join(
#   rbind(sra.all.df.fx(sra.2001.ls, 2001),
#         sra.all.df.fx(sra.2019.ls, 2019)),
#   rbind(sra.all.df.fx(sra.2001.inc.ls, 2001),
#         sra.all.df.fx(sra.2019.inc.ls, 2019)),
#   by = c("PMeco", "lyr_bot", "year"),
#   suffix = c("_bulk", "_inc"))
# sra.all.df <- sra.all.df %>%
#   mutate(PM = substr(PMeco, 1, 2),
#          ECO = substr(PMeco, 3, 4))
# 
# sra.all.df %>%
#   filter(d14c_inc > -130) %>%
#   ggplot(., aes(d14c_bulk, d14c_inc, color = PM)) +
#   geom_vline(xintercept = 0) +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_smooth(method = "lm", formula = y ~ x, aes(fill = PM)) +
#   geom_point() +
#   scale_color_manual(name = "Parent material",
#                      values = c("AN" = "blue",
#                                 "BS" = "red",
#                                 "GR" = "darkgray"),
#                      labels = c("AN" = "andesite",
#                                 "BS" = "basalt",
#                                 "GR" = "granite")) +
#     scale_fill_manual(name = "Parent material",
#                      values = c("AN" = "blue",
#                                 "BS" = "red",
#                                 "GR" = "darkgray"),
#                      labels = c("AN" = "andesite",
#                                 "BS" = "basalt",
#                                 "GR" = "granite")) +
#   coord_fixed(xlim = c(-130, 200), ylim = c(-130, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
#   
# summary(lm(d14c_inc ~ d14c_bulk * PM, sra.all.df[sra.all.df$d14c_inc > -130, ]))

# join all data as means and sds
sra.all.sum.df <- left_join(
  bind_rows(sra.2001.sum.ls2) %>%
    select(PMeco, lyr_bot, d14c_mean, d14c_sd) %>%
    mutate(Year = 2001) %>%
    bind_rows(., 
              bind_rows(lapply(sra.2019.ls, function(df) {
                df %>%
                  filter(lyr_bot < 31) %>%
                  select(PMeco, lyr_bot, d14c) %>%
                  group_by(PMeco, lyr_bot) %>%
                  summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                  mutate(Year = 2019)
                }))
            ),
  bind_rows(lapply(sra.2001.inc.ls, function(df) {
              df %>%
                select(PMeco, lyr_bot, d14c) %>%
                group_by(PMeco, lyr_bot) %>%
                summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                mutate(Year = 2001) 
              })) %>%
  bind_rows(., 
            bind_rows(lapply(sra.2019.inc.ls, function(df) {
              df %>%
                select(PMeco, lyr_bot, d14c) %>%
                group_by(PMeco, lyr_bot) %>%
                summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                mutate(Year = 2019)
              }))
            ), 
  by = c("PMeco", "lyr_bot", "Year"),
  suffix = c(".bulk", ".inc")) %>%
  mutate(PM = substring(PMeco, 1, 2),
         eco = substring(PMeco, 3, 4))

# simple linear regression of means
summary(lm(d14c_mean.inc ~ d14c_mean.bulk * PM, sra.all.sum.df[sra.all.sum.df$d14c_mean.inc > -200, ]))

Call:
lm(formula = d14c_mean.inc ~ d14c_mean.bulk * PM, data = sra.all.sum.df[sra.all.sum.df$d14c_mean.inc > 
    -200, ])

Residuals:
    Min      1Q  Median      3Q     Max 
-48.585 -19.180  -7.747  22.186  67.693 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)          71.7999     7.4744   9.606 3.67e-12 ***
d14c_mean.bulk        0.5137     0.1436   3.576 0.000894 ***
PMBS                -22.4831    10.5006  -2.141 0.038112 *  
PMGR                -49.6173    12.2047  -4.065 0.000206 ***
d14c_mean.bulk:PMBS   0.3595     0.2215   1.623 0.112049    
d14c_mean.bulk:PMGR   0.4387     0.1974   2.222 0.031731 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 28.85 on 42 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:   0.68, Adjusted R-squared:  0.6419 
F-statistic: 17.85 on 5 and 42 DF,  p-value: 0.000000001859
# lapply(split(sra.all.sum.df, sra.all.sum.df$eco), function(df) {
#   summary(lm(d14c_mean.inc ~ d14c_mean.bulk * PM, df))
# })

# # Deming regression (accounts for error in x and y terms)
# sra.dem <- lapply(split(sra.all.sum.df, sra.all.sum.df$PM), function(df) {
#   deming(d14c_mean.inc ~ d14c_mean.bulk,
#        data = df, xstd = d14c_sd.inc, ystd = d14c_sd.bulk)
# })

# all depths and years together, by PM
fig.n <- fig.n + 1
sra.19.inc.blk2  %>%
  bind_rows(., sra.01.inc.blk2[ , which(names(sra.19.inc.blk2) %in% names(sra.01.inc.blk2))]) %>%
  mutate(depth = factor(lyr_bot),
         ecoYear = paste0(eco, " (", Year, ")")) %>%
  filter(d14c_mean.inc > -200) %>%
  ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm)) +
  # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_vline(xintercept = 0) +
  # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_abline(slope = 1, intercept = 0) +
  geom_point(aes(color = pm, shape = ecoYear), size = 3) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  geom_errorbarh(
    aes(xmin = d14c_l.bulk, 
        xmax = d14c_u.bulk,
        color = pm), 
    height = 1.5) +
  geom_errorbar(
    aes(ymin = d14c_l.inc, 
        ymax = d14c_u.inc,
        color = pm), 
    width = 1.5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue",
                                "basalt" = "red",
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2019)" = 0,
                                "cool (2019)" = 1,
                                "cold (2019)" = 2,
                                "warm (2001)" = 15,
                                "cool (2001)" = 16,
                                "cold (2001)" = 17)) +
  coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
  xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
  ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
  # facet_grid(rows = vars(depth)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# # 2001
# sra.01.inc.blk2 %>%
#   filter(d14c_mean.bulk > -100 & d14c_mean.inc > -100) %>%
#   ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm, shape = eco, group = pm)) +
#   # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
#   geom_vline(xintercept = 0) +
#   # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_point(size = 3) +
#   geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
#   geom_errorbarh(
#     aes(xmin = d14c_l.bulk, 
#         xmax = d14c_u.bulk,
#         color = pm), 
#     height = 1.5) +
#   geom_errorbar(
#     aes(ymin = d14c_l.inc, 
#         ymax = d14c_u.inc,
#         color = pm), 
#     width = 1.5) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue",
#                                 "basalt" = "red",
#                                 "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 15,
#                                 "cool" = 16,
#                                 "cold" = 17)) +
#   coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   facet_grid(rows = vars(depth)) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
# 
# # 2019
# fig.n <- fig.n + 1
# sra.19.inc.blk2 %>%
#   mutate(depth = factor(lyr_bot)) %>%
#   ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm, shape = eco, group = pm)) +
#   # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
#   geom_vline(xintercept = 0) +
#   # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_point(size = 3) +
#   geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
#   geom_errorbarh(
#     aes(xmin = d14c_l.bulk, 
#         xmax = d14c_u.bulk,
#         color = pm), 
#     height = 1.5) +
#   geom_errorbar(
#     aes(ymin = d14c_l.inc, 
#         ymax = d14c_u.inc,
#         color = pm), 
#     width = 1.5) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue",
#                                 "basalt" = "red",
#                                 "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 0,
#                                 "cool" = 1,
#                                 "cold" = 2)) +
#   coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   facet_grid(rows = vars(depth)) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())

Fig. 7. Regression of 2019 bulk soil incubations and corresponding bulk soil \(\Delta\)14C

Caption: Regressions of \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2019. Error bars show one standard deviation for bulk soil, points show mean of three replicate profiles for bulk soils and single observations for respired CO2.

Time series: \(\Delta\)14C by depth (as measured)

# combine '01, '09, '19 data
sra.01.09.19.raw <- rbind(bind_rows(sra.2001.sum.ls),
                          bind_rows(sra.2019.sum.ls))
sra.2009.ls <- split(ras18.lyr, ras18.lyr$PMeco)
sra.2009.df <- bind_rows(sra.2009.ls)
colnames(sra.2009.df)[which(colnames(sra.2009.df) == "lyr_14c")] <- "d14c"
sra.2009.df <- sra.2009.df[ , which(names(sra.2009.df) %in% names(sra.01.09.19.raw))]
sra.2009.df <- cbind(sra.2009.df, 
                     fm = NA,
                     d14c_sd = NA,
                     fm_sd = NA,
                     d14c_u = NA,
                     d14c_l = NA)
sra.01.09.19.raw <- rbind(sra.01.09.19.raw, sra.2009.df)
sra.01.09.19.raw$Year <- factor(c(rep(2001, nrow(bind_rows(sra.2001.sum.ls))),
                                  rep(2019, nrow(bind_rows(sra.2019.sum.ls))),
                                  rep(2009, nrow(sra.2009.df))),
                                levels = c("2001", "2009", "2019"))

# plot
# w/ ribbons
# sra.01.09.19.raw %>%
#   mutate(PMeco_year = paste0(PMeco, Year),
#          eco = factor(ifelse(ECO == "pp", "warm",
#                       ifelse(ECO == "wf", "cool", "cold")),
#                       levels = c("warm", "cool", "cold")),
#          d14c_u = d14c + d14c_sd,
#          d14c_l = d14c - d14c_sd,
#          pm = ifelse(PM == "AN", "andesite",
#                      ifelse(PM == "BS", "basalt", "granite"))) %>%
#   ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
#   geom_vline(xintercept = 0) +
#   geom_hline(yintercept = 0) +
#   geom_ribbon(aes(xmin = d14c_l, xmax = d14c_u, fill = pm, alpha = Year, group = PMeco_year),
#               color = NA, show.legend = FALSE) +
#   geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 2) +
#   geom_point(aes(shape = eco), color = "black", size = 3) +
#   geom_path(aes(linetype = Year, color = pm), size = 0.7) +
#   scale_y_reverse() +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue", 
#                                 "basalt" = "red", 
#                                 "granite" = "darkgray")) +
#   scale_fill_manual(name = "Parent material",
#                     values = c("andesite" = "blue", 
#                                "basalt" = "red", 
#                                "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 22, 
#                                 "cool" = 21, 
#                                 "cold" = 24)) +
#   scale_alpha_manual(values = c("2001" = .6,
#                                 "2009" = 0.4,
#                                 "2019" = 0.2)) +
#   facet_grid(rows = vars(eco), cols = vars(pm)) +
#   xlab(expression(Delta*''^14*'C (‰)')) +
#   ylab("Depth (cm)") +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())

# litter
sra.2019.inc.L.df <- data.frame(
  sra.2019.inc_L.df %>%
    group_by(Year, PM, eco, lyr_bot, PMeco) %>%
    summarize(across(.cols = d14c, 
                     .fns = list(mean = mean, min = min, max = max))) %>%
    rename(year = Year, d14c = d14c_mean) %>%
    mutate(eco = factor(ifelse(eco == "pp", "warm",
                      ifelse(eco == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
           pm = ifelse(PM == "AN", "andesite",
                       ifelse(PM == "BS", "basalt", "granite"))))
# for plotting below
sra.2019.inc.L.df2 <- sra.2019.inc.L.df %>%
  rename(d14c_l = d14c_min,
         d14c_u = d14c_max) %>%
  mutate(PMeco_year = paste0(PMeco, year))

# with error bars, all depths
sra.01.09.19.raw %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 3.5) +
  geom_point(data = sra.2019.inc.L.df2, 
             aes(d14c, lyr_bot, color = pm, shape = eco), shape = 8, size = 3.5, show.legend = FALSE) +
  geom_path(aes(linetype = Year, color = pm), size = 0.7) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm,
        alpha = Year),
    height = 1.5) +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue",
                                "basalt" = "red",
                                "granite" = "darkgray")) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue",
                               "basalt" = "red",
                               "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15,
                                "cool" = 16,
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = 1,
                                   "2009" = 2,
                                   "2019" = 3)) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# just topsoil, w/ error bars
fig.n <- fig.n + 1
sra.01.09.19.raw <- sra.01.09.19.raw[order(sra.01.09.19.raw$lyr_top), ]
sra.01.09.19.raw %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 3) +
  geom_path(aes(linetype = Year, color = pm), size = 0.7) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm,
        alpha = Year),
    height = 1.5) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_x_continuous(limits = c(-160, 190)) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue", 
                               "basalt" = "red", 
                               "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                   "2009" = "dashed",
                                   "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Time series of \(\Delta\)14C by depth, as measured

Caption: Points show mean of three profile replicates for 2001, 2009, and 2019 samples. Error bars show ± 1 standard deviation of the mean (only a single profile was analyzed in 2009). Stars show litter incubation \(\Delta\)14C-CO2 for 2019 samples as a point of reference.

Spline fitting

Soils collected in both the 2001 and 2009 sampling campaigns were sampled by horizon, but the depth intervals differed between the two sampling years. In 2009, full profiles were excavated for each site, as opposed to the shorter profiles collected in 2001 from the GR and AN sites. Radiocarbon was measured on all three replicate profiles at each site for the 2001 samples, but only for one of the replicate profiles at each site in 2009, e.g. ANpp rep2, etc.

In order to compare the radiocarbon profiles between 2001, 2009, and 2019 we first interpolated both radiocarbon and carbon stock data at 1 cm intervals for each site in the datasets from each year. The carbon-stock-weighted radiocarbon values for any given target depth interval can then be calculated as a simple sum of the product of the carbon weight of each 1 cm increment (relative to the total carbon stock of the target depth interval) and its radiocarbon value. A monotonic cubic spline fit was used for the carbon stock interpolation (Wendt and Hauser 2013), and a mass-preserving spline was used to fit the radiocarbon data (Bishop, T.F.A., McBratney, A.B., Laslett, G.M., (1999) Modelling soil attribute depth functions with equal-area quadratic smoothing splines. Geoderma, 91(1-2): 27-45).

fig.n <- fig.n + 1
sra.01.09.19 %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  # filter(Year != "2009") %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, linetype = Year, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(alpha = Year), size = 3) +
  geom_path(aes(linetype = Year)) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  scale_y_reverse() +
  scale_x_continuous() +    
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                 "2009" = "dashed",
                                 "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Time series of bulk soil \(\Delta\)14C by 2001 depths (2001, 2009, 2019 samples)

Caption: Points for 2001 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2009 and 2019 samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2001. Error bars show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009).

fig.n <- fig.n + 1
sra.19.01.09 %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, linetype = Year, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(alpha = Year), size = 3) +
  geom_path(aes(linetype = Year)) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  # scale_y_reverse(limits = c(30, 0)) +
  scale_y_reverse() +
  scale_x_continuous() +    
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                   "2009" = "dashed",
                                   "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 7. Time series of bulk soil \(\Delta\)14C by depth (splined to 2019 depths)

Caption: Points for 2019 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2001 and 2009 samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2019. Error bars show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009). NB: Only two depth intervals were measured at the cool and cold andesite sites (max depth of 27 and 28 cm, respectively), so linear extrapolation (using the slope of the last 1cm spline-fitted depth increment) was used to extend the profiles to 30 cm.

# plot individual depths
fig.n <- fig.n + 1

# Atm
atm.14c <- data.frame(year = Datm[Datm$Date > 2000, "Date"],
                      d14c = Datm[Datm$Date > 2000, "NHc14"])
save(atm.14c, file = "atm.14c.RData")

# bulk 14C over time for 0-10, 10-20, 20-30 w/ atm
sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  mutate(PMeco_depth = paste0(PMeco, lyr_bot),
         depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         year = as.numeric(as.character(Year))) %>%
  ggplot(., aes(year, d14c)) +
  geom_path(data = atm.14c) +
  geom_point(aes(color = pm, shape = eco), size = 3) +
  geom_path(aes(color = pm, group = PMeco_depth, linetype = depth), alpha = 0.3) +
  geom_errorbar(
    aes(ymin = d14c_l, 
        ymax = d14c_u,
        color = pm), 
    width = .5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_linetype_manual(name = "Depth (cm)",
                        labels = c("10" = "0-10",
                                   "20" = "10-20",
                                   "30" = "20-30"),
                        values = c("10" = 1,
                                   "20" = 2,
                                   "30" = 3)) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab("Year") +
  theme_bw() +
  theme(panel.grid = element_blank())


### incubation
## 2019
sra.2019.inc.df <- bind_rows(lapply(sra.2019.inc.ls, function(df) {
  data.frame(df %>%
               group_by(Year, PM, ECO, lyr_bot, PMeco) %>%
               summarize(
                 across(.cols = d14c, 
                        .fns = list(mean = mean, min = min, max = max))) %>%
               rename(year = Year, d14c = d14c_mean))
}))
## 2001
sra.19.01.inc.df <- bind_rows(lapply(seq_along(sra.19.01.inc.ls), function(i) {
  PMeco <- names(sra.19.01.inc.ls)[i]
  d14c.ls <- lapply(sra.19.01.inc.ls[[i]], calc_14c, obs_date_y = 2001)
  df <- data.frame(d14c = d14c.ls[[1]],
                   d14c_min = d14c.ls[[2]],
                   d14c_max = d14c.ls[[3]],
                   lyr_bot = c(10, 20, 30),
                   PMeco = PMeco,
                   PM = substr(PMeco, 1, 2),
                   ECO = substr(PMeco, 3, 4),
                   year = 2001)
  return(df)
}))
sra.19.01.inc <- rbind(sra.19.01.inc.df, sra.2019.inc.df)

# plot
sra.19.01.inc %>%
  mutate(PMeco_depth = paste0(PMeco, lyr_bot),
         depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(year, d14c)) +
  geom_path(data = atm.14c) +
  geom_point(aes(color = eco, shape = eco), size = 3) +
  geom_point(data = sra.2019.inc.L.df, aes(color = eco), shape = 8, size = 3, show.legend = FALSE) +
  geom_path(aes(color = eco, group = PMeco), alpha = 0.3) +
  geom_errorbar(
    aes(ymin = d14c_min, 
        ymax = d14c_max,
        color = eco), 
    width = .5) +
  geom_errorbar(
    data = sra.2019.inc.L.df,
    aes(ymin = d14c_min, 
        ymax = d14c_max,
        color = eco), 
    width = .5) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_y_continuous(limits = c(-40, 170)) +
  facet_grid(rows = vars(pm), cols = vars(depth)) +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab("Year") +
  theme_bw() +
  theme(panel.grid = element_blank())


# plot inc and bulk together, by depth
sra.ts.all <- sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  select(Year, PM, ECO, PMeco, lyr_bot, d14c, d14c_sd) %>%
  mutate(Type = "bulk",
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         year = as.numeric(as.character(Year))) %>%
  select(-d14c_sd) %>%
  bind_rows(.,
            sra.19.01.inc %>%
              select(year, PM, ECO, PMeco, lyr_bot, d14c, d14c_min, d14c_max) %>%
              rename(d14c_l = d14c_min,
                     d14c_u = d14c_max) %>%
              mutate(Type = "inc")
  ) %>%
  mutate(depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         ecoType = paste0(eco, " (", Type, ")"))

# Plot by depth
plot.ts.fx <- function(df) {
  df %>%
    filter(d14c > -200) %>%
    filter(year != 2009) %>%
    ggplot(., aes(year, d14c)) +
    geom_path(data = atm.14c) +
    geom_point(aes(color = pm, shape = ecoType), size = 3) +
    geom_path(aes(color = pm, linetype = Type), alpha = 0.3) +
    geom_errorbar(
      aes(ymin = d14c_l, 
          ymax = d14c_u,
          color = pm), 
      width = .5) +
    scale_color_manual(name = "Parent material",
                       values = c("andesite" = "blue", 
                                  "basalt" = "red", 
                                  "granite" = "darkgray")) +
    scale_shape_manual(name = "Ecosystem (type)",
                       values = c("warm (inc)" = 0,
                                  "cool (inc)" = 1,
                                  "cold (inc)" = 2,
                                  "warm (bulk)" = 15,
                                  "cool (bulk)" = 16,
                                  "cold (bulk)" = 17)) +
    facet_grid(rows = vars(eco), cols = vars(pm)) +
    ylab(expression(Delta*''^14*'C (‰)')) +
    xlab("Year") +
    theme_bw() +
    theme(panel.grid = element_blank())
}

# plots
lapply(split(sra.ts.all, sra.ts.all$depth), plot.ts.fx)
$`10`

$`20`

$`30`

# # to save
# for(i in 1:3) ggsave(paste0(i, ".pdf"), lapply(split(sra.ts.all, sra.ts.all$depth), plot.ts.fx)[[i]])

Fig. 7. Change in \(\Delta\)14C of bulk soil (panel a) and respired CO2 (panel b) over time relative to the atmosphere

Caption: Points for 2019 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2001 and 2009 (bulk only) samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2019. Error bars for bulk samples in panel (a) show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009); error bars for incubation samples in panel (b) show the values of the two reps, while the point represents the mean. NB: Only two depth intervals were measured at the cool and cold andesite sites (max depth of 27 and 28 cm, respectively), so linear extrapolation (using the slope of the last 1cm spline-fitted depth increment) was used to extend the profiles to 30 cm.

# join w/ d14c
sra.all.min <- ras18.sp.df %>%
  mutate(pm = ifelse(PM == "AN", "andesite", ifelse(PM == "BS", "basalt", "granite")),
         eco = ifelse(ECO == "pp", "warm", ifelse(ECO == "wf", "cool", "cold"))) %>%
  # mutate(Al_nonCrys = Al_ox - Al_py,
  #        Fe_Crys = Fe_dc - Fe_ox) %>%
  select(-PM, -ECO, -pro_name) %>%
  left_join(sra.ts.all.blk.inc[ , c("pm", "eco", "lyr_bot", "year", "d14c_bulk", "d14c_u_bulk", "d14c_inc", "d14c_u_inc", "d14c_l_inc", "d14c_l_bulk", "blk.inc", "blk.inc.sd")], 
            ., 
            by = c("pm", "eco", "lyr_bot")) %>%
  pivot_longer(cols = c("Al_py", "Al_ox", "Fe_ox", "Fe_dc", "Al_nonCrys", "Fe_Crys"), names_to = "min", values_to = "conc")
Error: Can't subset columns that don't exist.
x Column `Al_nonCrys` doesn't exist.

# function for Tukey HSD tables
tukey.table.fx <- function(x, year, type, var) {
  depth <- paste0(unique(x$lyr_bot) - 10, "-", unique(x$lyr_bot), " cm")
  if (type == "inc") {
    x <- x[x$d14c > -200, c("d14c", var)]
  } 
  return(
    TukeyHSD(aov(reformulate(var, "d14c"), x))[var] %>%
    data.frame(.) %>%
    mutate(Pairs = rownames(.)) %>%
    mutate(across(where(is.numeric), round, 3)) %>%
    gt() %>%
    tab_header(
      title = depth,
      subtitle = paste(year, type, var)
    ))
}

### 2001
## bulk
sra.2001.bulk.df <- bind_rows(
  lapply(sra.19.01.rep.ls, function(ls) {
    ls <- lapply(ls, function(x) x[complete.cases(x)])
    d14c <- calc_14c(unlist(ls), 2001)
    df <- data.frame(d14c = d14c,
                     lyr_bot = rep(c(10, 20, 30), length(d14c) / 3))
    return(df)
  }),
  .id = "PMeco") %>%
  mutate(PM = substr(PMeco, 1, 2),
         ECO = substr(PMeco, 3, 4))
# PM
# lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x))
# })
lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "bulk", "PM")
})
# ECO
# lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x))
# })
lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "bulk", "ECO")
})

## inc
sra.2001.inc.df2 <- cbind(sra.19.01.inc.df[rep(1:nrow(sra.19.01.inc.df), 2), c("PM", "ECO", "lyr_bot")],
                          d14c = c(sra.19.01.inc.df$d14c_min, sra.19.01.inc.df$d14c_max))
save(sra.2001.inc.df2, file = "sra.2001.inc.df2.RData")
# PM
# lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "inc", "PM")
})
# ECO
# lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "inc", "ECO")
})

### 2019
## bulk
sra.2019.bulk.df <- bind_rows(sra.2019.ls)
# PM
# lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
#   if (nrow(x) == 27) summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
  if (nrow(x) == 27) tukey.table.fx(x, "2019", "bulk", "PM")
})
# ECO
# lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
#   if (nrow(x) == 27) summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
  if (nrow(x) == 27) tukey.table.fx(x, "2019", "bulk", "ECO")
})
## inc
sra.2019.inc.df2 <- bind_rows(sra.2019.inc.ls)
save(sra.2019.inc.df2, file = "sra.2019.inc.df2.RData")
# PM
# lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2019", "inc", "PM")
})
# ECO
# lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2019", "inc", "ECO")
})

# compare 2001 and 2019
# bulk
sra.01.19.bulk.df <- data.frame(
  rbind(sra.2001.bulk.df, 
        sra.2019.bulk.df[, which(names(sra.2019.bulk.df) %in% names(sra.2001.bulk.df))]),
  year = as.factor(c(rep(2001, nrow(sra.2001.bulk.df)), rep(2019, nrow(sra.2019.bulk.df))))) %>%
  filter(lyr_bot < 31)
sra.01.19.bulk.ls <- split(sra.01.19.bulk.df, sra.01.19.bulk.df$PMeco)
lapply(sra.01.19.bulk.ls, function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PMeco), " 2001 vs. 2019"), "bulk", "year")
  })
})
# by PM
lapply(split(sra.01.19.bulk.df, sra.01.19.bulk.df$PM), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PM), " 2001 vs. 2019"), "bulk", "year")
  })
})
# by ECO
lapply(split(sra.01.19.bulk.df, sra.01.19.bulk.df$ECO), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$ECO), " 2001 vs. 2019"), "bulk", "year")
  })
})
# inc
sra.01.19.inc.df <- data.frame(
  d14c = c(sra.19.01.inc[ , "d14c_min"],
           sra.19.01.inc[ , "d14c_max"]),
  sra.19.01.inc[ , c("PMeco", "lyr_bot", "PM", "ECO", "year")]) %>%
  mutate(year = as.factor(year))
sra.01.19.inc.ls <- split(sra.01.19.inc.df, sra.01.19.inc.df$PMeco)
lapply(sra.01.19.inc.ls, function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PMeco), " 2001 vs. 2019"), "inc", "year")
  })
})
lapply(split(sra.01.19.inc.df, sra.01.19.inc.df$PM), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PM), " 2001 vs. 2019"), "inc", "year")
  })
})
lapply(split(sra.01.19.inc.df, sra.01.19.inc.df$ECO), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$ECO), " 2001 vs. 2019"), "inc", "year")
  })
})

# color palettes for ECO & PM
warm <- "#BF812D"
cool <- "#80CDC1"
cold <- "#01665E"
granite <- "#9daba9"
andesite <- "#382dbf"
basalt <- "#bf382d"

# plot fx
boxplot.fx <- function(df, var, year, type, topsoil = FALSE, subsoil = FALSE) {
  atm <- ifelse(year == "2001", atm.d14.2001, atm.d14.2019)
  if (type == "inc") {
    df <- df[df$d14c > -200, ]
    ylim <- c(-65, 165)
  } else {
    if (topsoil) {
      df <- df[df$lyr_bot < 31, ]
      ylim <- c(-120, 165)
      }
    if (subsoil) {
      df <- df[df$lyr_bot > 31, ]
      ylim <- c(-270, 65)
    }
  }
  if (var == "PM") {
    df %>%
      mutate(pm = factor(ifelse(PM == "GR", "granite",
                                ifelse(PM == "AN", "andesite", "basalt")),
                         levels = c("granite", "andesite", "basalt"))) %>%
      group_by(pm, lyr_bot) %>%
      ggplot(., aes(pm, d14c)) +
      geom_hline(yintercept = atm, linetype = "dotted", alpha = 0.3) +
      geom_hline(yintercept = 0) +
      geom_boxplot(aes(color = pm), lwd = 1) +
      scale_color_manual(values = c("andesite" = andesite,
                                    "basalt" = basalt,
                                    "granite" = granite),
                         guide = "none") +
      scale_y_continuous(limits = ylim) +
      facet_grid(cols = vars(lyr_bot)) +
      ylab(expression(Delta*''^14*'C (‰)')) +
      ggtitle(paste(year, type)) +
      theme_bw() +
      theme(panel.grid = element_blank(),
            text = element_text(size = 14))
  } else {
    df %>%
      mutate(eco = factor(ifelse(ECO == "pp", "warm",
                                 ifelse(ECO == "wf", "cool", "cold")),
                          levels = c("warm", "cool", "cold"))) %>%
      group_by(eco, lyr_bot) %>%
      ggplot(., aes(eco, d14c)) +
      geom_hline(yintercept = atm, linetype = "dotted", alpha = 0.3) +
      geom_hline(yintercept = 0) +
      geom_boxplot(aes(color = eco), lwd = 1) +
      scale_color_manual(values = c("warm" = warm,
                                    "cool" = cool,
                                    "cold" = cold),
                         guide = "none") +
      scale_y_continuous(limits = ylim) +
      facet_grid(cols = vars(lyr_bot)) +
      ylab(expression(Delta*''^14*'C (‰)')) +
      ggtitle(paste(year, type)) +
      theme_bw() +
      theme(panel.grid = element_blank(),
            text = element_text(size = 14))
  }
}

# bulk
boxplot.fx(sra.2001.bulk.df, "PM", "2001", "bulk", topsoil = TRUE)
boxplot.fx(sra.2019.bulk.df, "PM", "2019", "bulk", topsoil = TRUE)
boxplot.fx(sra.2001.bulk.df, "ECO", "2001", "bulk", topsoil = TRUE)
boxplot.fx(sra.2019.bulk.df, "ECO", "2019", "bulk", topsoil = TRUE)
boxplot.fx(sra.2019.bulk.df, "ECO", "2019", "bulk", subsoil = TRUE)
# inc
boxplot.fx(sra.2001.inc.df2, "PM", "2001", "inc")
boxplot.fx(sra.2019.inc.df2, "PM", "2019", "inc")
boxplot.fx(sra.2001.inc.df2, "ECO", "2001", "inc")
boxplot.fx(sra.2019.inc.df2, "ECO", "2019", "inc")
# data, unsummarized
sra.ts.all.raw <- rbind(
  sra.2001.bulk.df[ , names(sra.2001.bulk.df) %in% names(sra.2001.inc.df2)],
  sra.2019.bulk.df[ , names(sra.2019.bulk.df) %in% names(sra.2001.inc.df2)],
  sra.2001.inc.df2,
  sra.2019.inc.df2[ , names(sra.2019.inc.df2) %in% names(sra.2001.inc.df2)]) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = factor(ifelse(PM == "GR", "granite",
                                ifelse(PM == "AN", "andesite", "basalt")),
                         levels = c("granite", "andesite", "basalt")),
         Type = c(rep("bulk", length = nrow(sra.2001.bulk.df)),
                  rep("bulk", length = nrow(sra.2019.bulk.df)),
                  rep("inc", length = nrow(sra.2001.inc.df2)),
                  rep("inc", length = nrow(sra.2019.inc.df2))),
         year = c(rep(2001, length = nrow(sra.2001.bulk.df)),
                  rep(2019, length = nrow(sra.2019.bulk.df)),
                  rep(2001, length = nrow(sra.2001.inc.df2)),
                  rep(2019, length = nrow(sra.2019.inc.df2))))

# plot fx
ts.groupPlot.fx <- function(df, x, y) {
  quo_x <- sym(x)
  quo_y <- sym(y)
  if (x == "pm") {
    var.name <- "Parent material"
    var.values <- c("andesite" = andesite,
                    "basalt" = basalt,
                    "granite" = granite) 
  } else {
    var.name <- "Climate"
    var.values <-  c("warm" = warm,
                     "cool" = cool,
                     "cold" = cold)
  }
  plot.df <- df %>%
    filter(d14c > -200) %>%
    filter(lyr_bot < 31) %>%
    group_by(!! quo_x, lyr_bot, Type, year) %>%
    summarize(across(d14c, list(mean = mean, sd = sd)))
  if (y == "dd14c") {
    plot.df <- plot.df %>%
      mutate(atm = ifelse(year == 2001, atm.d14.2001, atm.d14.2019),
             dd14c = d14c_mean - atm,
             u = d14c_mean + d14c_sd - atm,
             l = d14c_mean - d14c_sd - atm)
    atm.df <- atm.14c
    atm.df$d14c <- 0
    ylab <- expression(Delta*Delta*''^14*'C (‰)') 
    } else {
      plot.df <- plot.df %>%
        mutate(u = d14c_mean + d14c_sd,
               l = d14c_mean - d14c_sd)
      atm.df <- atm.14c
      ylab <- expression(Delta*''^14*'C (‰)') 
    }
    ggplot(plot.df, aes(year, !! quo_y)) +
    geom_path(data = atm.df, aes(year, d14c)) +
    geom_path(aes(color = !! quo_x, linetype = Type), alpha = .5, lwd = 1) +
    geom_point(aes(color = !! quo_x), 
               size = 3, position = position_dodge(width = 1)) +
    geom_errorbar(
      aes(ymin = l,
          ymax = u,
          color = !! quo_x,
          alpha = Type),
      width = 1,
      position = position_dodge(width = 1)) +
    scale_color_manual(name = var.name,
                       values = var.values) +
    scale_fill_manual(name = "±SD",
                      values = var.values) +
    scale_alpha_manual(values = c("bulk" = 1,
                                  "inc" = .5)) +
    facet_grid(cols = vars(lyr_bot)) +
    ylab(ylab) +
    xlab("Year") +
    theme_bw() +
    theme(panel.grid = element_blank())
}
# plot
ts.groupPlot.fx(sra.ts.all.raw, "pm", "dd14c")
ts.groupPlot.fx(sra.ts.all.raw, "eco", "dd14c")
ts.groupPlot.fx(sra.ts.all.raw, "pm", "d14c_mean")
ts.groupPlot.fx(sra.ts.all.raw, "eco", "d14c_mean")

Initial modeling

The goal of this modeling exercise is to see how parent material and climate/ecosystem affect estimates of soil carbon ages and transit times. Bulk soil 14C observations from 2001, 2009, and 2019 will be used to constrain the carbon models, as well as observations of 14C-CO2 from laboratory soil incubations of soils collected in 2001 and 2019. Previous work has indicated that the carbon stocks at these sites is likely at equilibrium, so we will apply the steady-state assumption to the modeling.

Two-pool models

One pool models have been shown repeatedly to be inadequate for describing soil carbon dynamics. However, as simple models are easier to constrain, we will start with a two-pool parallel and two-series models, as these are the simplest model system beyond the single pool approach.

The two-pool parallel model requires the following parameters: * decomposition constants for each pool (k1, k2) * input partitioning coefficient (\(\gamma\)) * steady-state carbon stocks (C) * inputs (I) * initial values of 14C 1 The two-pool series model requires the following parameters: * decomposition constants for each pool (k1, k2) * transfer coefficient (\(\alpha\)) * steady-state carbon stocks (C) * inputs (I) * initial values of 14C

Decomposition rates (k) are related to the amount of 14C in a pre-bomb system (fraction modern, F) at steady-state by the following equations (cf. Schuur, Druffle, and Trumbore, 2016): >Eq. 1

\[F = \frac{k}{k + \lambda}\] >Eq. 2

\[k = \frac{\lambda \cdot F}{1 - F}\] >where \(\lambda\) is the radioactive decay constant (1/8267).

As the decomposition rates will vary, the initial 14C content can be determined dynamically with equation 1.

Carbon stocks are known, while inputs will be estimated and are related to the steady-state conditions by the following equation: >Eq. 3

\[I = (k_{1} \cdot C_{1}) + (k_{2} \cdot C_{2})\] >where C1 and C2 are the carbon stocks of the two model pools.

Both stocks and inputs can be scaled to the known value of the total carbon pool once the steady-state parameters (k1, k2, and \(\gamma\) or \(\alpha\)) have been determined. Pool sizes are a function of the inputs and input partitioning coefficient at steady-state.

A Monte-Carlo Markov chain approach will be used for parameter estimation in combination with an initial optimization algorithm to determine the best set of initial parameters.

Workflow

Initial model fitting was performed for both model structures using generous parameter ranges [0, 1] for all three parameters (k1, k2, \(\gamma\) or \(\alpha\)). The initial parameter set was found by fitting the models by eye, followed by optimization with the function “modFit” (R package FME), using the Nelder-Mead algorithm. The best set of parameters found by modFit was then used as the input to a Monte Carlo Markov Chain (MCMC), using the function “modMCMC” (R package FME). The number of iterations for the MCMC optimization was set at 5000 intially, with delayed rejection employed to increase efficiency.

The sum of the mean squared error for the best parameter set was slightly lower for the parallel structure than for the series structure. Additionally, the overall mean error of the residuals was also lower for the parallel structure, moderately so for the bulk C observations but substantially so for the respiration observations (in andesite and granite soils in particular).

However, these initial fits yielded unrealistic parameter estimates for multiple sites, particularly at the lower depths. Additionally, the modFit output showed very high correlation between the parameters for both model structures (slightly higher for the two-pool series model).

# k from fraction modern
k <- function (Fm) {
  (Fm * lambda)/(1 - Fm)
}

# d14C from fraction modern 
fm_14c <- function (fm, date) {
  (fm * exp(lambda * (1950 - date)) - 1) * 1000
}

# pre-bomb fraction modern from k (steady-state assumed)
fm <- function (k){
  k/(k + lambda)
}
# index of years for which bulk/resp 14C are known
year.ix <- c(which(Datm$Date == 2001.5),
             which(Datm$Date == 2009.5),
             which(Datm$Date == 2019.5))

# function for saving constraint data in a dataframe for plotting in ggplot'
con.df.fx <- function(PMeco_depth) {
  bulk.df <- obs.bulk.14c[[PMeco_depth]]
  resp.df <- obs.resp.14c[[PMeco_depth]]
  return(
    con.df <- data.frame(pool = c(rep("bulk C", nrow(bulk.df)), rep("respiration", nrow(resp.df))),
                         d14c = c(bulk.df$bulkC, resp.df$resp),
                         Year = c(bulk.df$time, resp.df$time)))
}

# plot function
C14.2p.plot.fx <- function(plot.df, con.df, mod, PMeco_depth) {
  plot.df %>%
  filter(pool == "bulk C" | pool == "respiration" | pool == "atm") %>%
  ggplot(., aes(years, d14C, color = pool)) +
  geom_path() +
  geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
  scale_color_manual(
    name = "Pool",
    values = c("atm" = 8,
               "bulk C" = "black",
               "fast" = "#D81B60",
               "slow" = "#1E88E5",
               "respiration" = "#FFC107")) +
  scale_x_continuous(limits = c(1950, 2022)) +
  ggtitle(paste(PMeco_depth, mod)) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
}
C14.1p.plot.fx <- function(plot.df, con.df, mod, PMeco_depth) {
  ggplot(plot.df, aes(years, d14C, color = pool)) +
  geom_path() +
  geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
  scale_color_manual(
    name = "Pool",
    values = c("atm" = 8,
               "bulk C" = "black",
               "respiration" = "#FFC107")) +
  scale_x_continuous(limits = c(1950, 2022)) +
  ggtitle(paste(PMeco_depth, " 1p bulk + 1p resp")) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
}

# set up model function for optimization
# NOTE: par[3] for 2ps model changed to proportion transferred (no longer = a21)
# therefore, a21 = par[3] * par[1]
modFun_2p <- function(pars, In, lag = 0, pass = TRUE, out = "modFit", mod) {
 
  # intial 14C
  F0_Delta14C <- unlist(lapply(pars[1:2], function(x) Delta14C_from_AbsoluteFractionModern(fm(x))))
  
  # model matrix
  A <- -diag(pars[1:2])
  if (mod == "2ps") {
    a21 <- pars[3] * pars[1]
    A[2, 1] <- a21
  }
    
  # steady-state C stocks
  if (mod == "2pp") {
    ss.cstock <- (-1 * solve(A) %*% c(In * pars[3], In * (1 - pars[3])))
  } else {
    ss.cstock <- (-1 * solve(A) %*% c(In, 0))
  }
  
  # time index
  ix.t <- c((lag + 1):nrow(Datm))
  
  # model
  if (mod == "2pp") {
    mod <- TwopParallelModel14(t = Datm$Date[ix.t],
                               ks = pars[1:2],
                               C0 = c(ss.cstock[1], ss.cstock[2]),
                               F0_Delta14C = F0_Delta14C,
                               In = In,
                               gam = pars[3],
                               inputFc = Datm,
                               lag = lag,
                               pass = pass)
  } else {
    mod <- TwopSeriesModel14(t = Datm$Date[ix.t],
                             ks = pars[1:2],
                             C0 = c(ss.cstock[1], ss.cstock[2]),
                             F0_Delta14C = F0_Delta14C,
                             In = In,
                             a21 = a21,
                             inputFc = Datm,
                             lag = lag,
                             pass = pass)
  }
  
  # get mod values
  C14m <- getF14C(mod)
  C14p <- getF14(mod)
  C14r <- getF14R(mod)
  Ctot <- getC(mod)
  
  if(out == "modFit") {
    # dataframe for modFit fx
    return(data.frame(
      time = Datm$Date[ix.t],
      bulkC = C14m, 
      resp = C14r,
      cStock = rowSums(Ctot)))
  } else {
    # data frame for plotting
    return(data.frame(
      years = rep(Datm$Date[ix.t], 5),
      d14C = c(C14p[,1], 
               C14p[,2], 
               C14m,
               C14r,
               Datm$NHc14[ix.t]),
      pool = rep(c("fast", "slow", "bulk C", "respiration", "atm"), each = nrow(C14p))))
  }
}

# 1p modFun
modFun_1p <- function(pars, In, lag = 0, out = "modFit", mod, pass = TRUE) {
 
  # intial 14C
  F0_Delta14C <- Delta14C_from_AbsoluteFractionModern(fm(pars))
  
  # steady-state C stocks
  ss.cstock <- In/pars
  
  # time index
  ix.t <- c((lag + 1):nrow(Datm))
  
  # model
  mod <- suppressWarnings(
    # warnings suppressed due to the "Fc" warning
    OnepModel14(t = Datm$Date[ix.t],
                     k = pars,
                     C0 = ss.cstock,
                     F0_Delta14C = F0_Delta14C,
                     In = In,
                     inputFc = Datm,
                     lag = lag,
                     pass = pass)
  )
  
  # get mod values
  C14m <- getF14C(mod)
  Ctot <- getC(mod)
  
  if(out == "modFit") {
    # dataframe for modFit fx
    return(data.frame(
      time = Datm$Date[ix.t],
      bulkC = C14m,
      cStock = Ctot))
  } else {
    # data frame for plotting
    return(data.frame(
      years = rep(Datm$Date[ix.t], 1),
      d14C = c(C14m,
               Datm$NHc14[ix.t]),
      pool = rep(c("bulk C", "atm"), each = length(C14m))))
  }
}

# function for trial and error approach to finding initial parameter set
par.fx <- function(pars, In, lag = 0, out = "plot.df", verbose = TRUE, mod, pass = FALSE) {
  
  # model matrix
  A <- -diag(pars[1:2])
  if (mod == "2ps") {
    a21 <- pars[3] * pars[1]
    A[2, 1] <- a21
    # steady-state stocks
    ss.cstock <- round((-1 * solve(A) %*% c(In, 0)), 1)
  } else if (mod == "2pp") {
    # steady-state stocks
    ss.cstock <- round((-1 * solve(A) %*% c(In * pars[3], In * (1 - pars[3]))), 1)
  } else {
    ss.cstock <- In/pars
  }
  
  cstock.sum <- ifelse(length(ss.cstock) == 1, ss.cstock, colSums(ss.cstock))
  
  # print site and steady-state stocks
  if (verbose) {
    cat(paste0(PMeco_depth, "\n"))
    if (mod == "2ps" | mod == "2pp") {
      cat(paste0(ss.cstock[1], " (fast pool)\n", ss.cstock[2], " (slow pool)\n"))
      cat(paste0("slow pool: ", round(ss.cstock[2] / cstock.sum * 100, 0), "%\n")) 
    }
    cat(round(cstock.sum, 1), " (modeled stocks)\n")
    cat(round(csoc.19.0_30[[PMeco_depth]][ , "lyr_soc"], 1), " (measured stocks)\n") 
  }
  if (mod == "1p") {
    return(modFun_1p(pars = pars, In = In, lag = lag, out = out, mod = "1p", pass = pass))
  }
  if (mod == "2pp") {
   return(modFun_2p(pars = pars, In = In, lag = lag, out = out, mod = "2pp", pass = pass)) 
  } else if (mod == "2ps") {
    return(modFun_2p(pars = pars, In = In, lag = lag, out = out, mod = "2ps", pass = pass)) 
  }
}
## adjust inputs to match stocks
# function for calculating steady-state SOC stocks
soc.fx <- function(modStr, pars, In, out = "pools") {
  if (modStr == "2pp") {
    cmat <- -1 * solve(-diag(pars[1:2])) %*% c(In * pars[3], In * (1 - pars[3]))
  } else {
    A <- -diag(pars[1:2])
    A[2, 1] <- pars[3] # note that a21 defined as pct transfer * k1
    cmat <- -1 * solve(A) %*% c(In, 0) # In is total input into the system
  }
  if (out == "pools") {
    return(cmat)
  } else {
    return(colSums(cmat))
  }
}

in.fit.fx <- function(modStr, pars, initialIn, SOC) {
  # sequence of possible input values
  if  (SOC < soc.fx(modStr, pars, initialIn, out = "sum")) {
    ins <- seq(.01, 
               initialIn, 
               .01)
    } else {
      ins <- seq(initialIn, 
                 SOC, 
                 .01)
    }
  # modeled stocks
  soc_mod <- lapply(seq_along(ins), function(j) {
    soc.fx(modStr, pars, ins[j], out = "sum")
  })
  ix <- which.min(abs(unlist(soc_mod) - SOC))
  return(ins[ix])
}

# load initial parameter set
load("../data/derived/modFit_pars/pars.i.2pp_2021-03-30.Rdata")
load("../data/derived/modFit_pars/pars.i.2ps_2020-11-16.Rdata")

## inputs for initial par set and measured stocks
# 2pp
in.meas.2pp <- lapply(seq_along(pars.i.2pp[ix.10]), function(i) {
  PMeco_depth <- names(pars.i.2pp[ix.10])[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.i.2pp[ix.10][[i]], in.i[ix.10][[i]], SOC))
})
names(in.meas.2pp) <- names(pars.i.2pp[ix.10])
# 2ps
in.meas.2ps <- lapply(seq_along(pars.i.2ps[ix.10]), function(i) {
  PMeco_depth <- names(pars.i.2ps[ix.10])[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.i.2ps[ix.10][[i]], in.i[ix.10][[i]], SOC))
})
names(in.meas.2ps) <- names(pars.i.2ps[ix.10])

# Flux estimated from Goulden et al. 2012; Tang et al. 2005; Wang et al. 2000; Gaudinski 2000
# fluxes by elevation from GPP reported in Goulden et al. Fig. 5 and approximated
# Rh percentage from Tang et al. 2005 = 0.44 (ann. mean Blodgett); cf. 0.48 Harvard Forest
# A horizon est. 0.55 from Gaudinski
# assuming A = 0-30, assume 0-10 = 50%, 10-20 = 30%, 20-30 = 20% of total A production 
hznA.Rh.kgm2 <- 0.44 * 0.55 * 10^-3
gpp.ls <- c(1800, 1600, 1400)
in.frc.ls <- c(0.5, 0.3, 0.2)

# fx for calculating inputs
in.flx.fx <- function(PMeco_depth) {
  gpp <- ifelse(grepl("pp", PMeco_depth), gpp.ls[1], ifelse(grepl("wf", PMeco_depth), gpp.ls[2], gpp.ls[3]))
  in.frc <- ifelse(grepl("0-10", PMeco_depth), in.frc.ls[1], ifelse(grepl("10-20", PMeco_depth), in.frc.ls[2], in.frc.ls[3]))
  return(gpp * in.frc * hznA.Rh.kgm2)
}

# input list
in.est <- lapply(seq_along(pars.i.2pp), function(i) {
  PMeco_depth <- names(pars.i.2pp)[i]
  return(in.flx.fx(PMeco_depth))
})
names(in.est) <- names(pars.i.2pp)

Parameter optimization

Optimizing the parameter set requires imposing costs and optionally constraining the allowable range of values for each parameter. Given that we only have data for three time points, this is a relatively sparse data set for constraining these models. Accordingly, the optimization procedure will benefit from a priori constraints of the allowable parameter ranges. For example, since we assume that the system cannot be adequately modeled as a single homogenous reservoir, we will ensure that the optimization procedure cannot collapse the two-pool system into a single pool. This can be mitigated in the two-pool parallel optimization by constraining \(\gamma\) (i.e. the percentage of the inputs entering the fast pool) to a range of 50% to 95%. Similarly, for the two-pool series model structure we can constrain the range of the transfer coefficient to be between 0.0 and 0.1, ensuring that some carbon remains in the fast cycling pool.

Additionally, to enforce a relatively fast cycling pool and relatively slower cycling pool, we will loosely constrain the intrinsic decomposition rates as well (both model structures):

k1: [0.02, 1.00] (50 to 1 year) k2: [0.0001, 0.02] (10,000 to 50 years)

Finally, the models will be run to enforce steady-state, i.e. with unvarying carbon stocks. The amount of carbon observed in the system will be used in the cost function in addition to the radiocarbon observations made in 2001, 2009, and 2019. The inputs will be estimated from net ecosystem exchange (NEE) data measured at nearby eddy covariance sites: Blodgett experimental forest (AmeriFlux), Lower Teakettle (NEON), and Soaproot Saddle (NEON). Alternatively, using correlations between fluxes measured from these eddy covariance towers and GPP estimated from satellite retrievals of SIF, estimates can be made for inputs at the pixels corresponding to each site location.

# Note: this only runs if eval flag switched to TRUE
## Optimize model pars
# Cost function (evaluates error as model vs. obsv, per FME req)
# note that we have to set "pass" to TRUE so SoilR model doesn't fail (neg. resp)
mod.fits.fx <- function(mod, pars, In, sub, lag = 0, upper, lower, cost) {
  
  # start loop
  lapply(seq_along(pars[sub]), function(i) {
    
    # start timer and print PMeco_depth
    start <- Sys.time()
    cat(paste0(names(pars)[sub][i], " parameter fitting\n"))
  
    # define pars
    pars <- pars[sub][[i]]
    if (mod == "2pp") {
      names(pars) <- c("k1", "k2", "gam")
    } else {
      names(pars) <- c("k1", "k2", "tc")
    }
    
    # Set input
    In <- In[sub][[i]]
    
    # define cost function
    if (cost == "14C + cStock") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        cost2 <- modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1) 
        return(modCost(model = modelOutput, obs = obs.cStock[sub][[i]], cost = cost2))
      }
    } else if (cost == "14C + stock/flx") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        cost2 <- modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1) 
        return(modCost(model = modelOutput, obs = obs.flx.stock[[i]], cost = cost2))
      }
    } else if (cost == "14C") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        return(modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1))
      } 
    } else if (cost == "14C bulk + cStock") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        return(modCost(model = modelOutput, obs = obs.cStock[sub][[i]], cost = cost1))
      }
    } else if (cost == "14C bulk only") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        return(modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE))
      }
    }
    
    # fit pars
    fit <- tryCatch(
      modFit(f = mod.Cost,
             p = pars,
             method = 'Nelder-Mead',
             upper = upper, 
             lower = lower),
      error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
    
    Sfun <- sensFun(mod.Cost, fit$par)
    
    # End timer and print elapsed time
    end <- Sys.time()
    cat(paste0("time: ", end - start, "\n"))
    
    # Return fitted parameters and sensitivity
    return(list(modfit = fit, 
                sens = Sfun))
  }) 
}

## 2pp
# par range [0, 1] for all pars
mod.sens.fits.2pp <- mod.fits.fx(mod = "2pp",
                                 pars = pars.i.2pp,
                                 In = in.i,
                                 sub = ix.10,
                                 upper = c(1, 1, 1),
                                 lower = c(0, 0, 0),
                                 cost = "14C")
names(mod.sens.fits.2pp) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp <- lapply(mod.sens.fits.2pp, function(x) x[[1]])
# constrain gamma to [0.5, 0.95]
mod.sens.fits.2pp.p3.5.95 <- mod.fits.fx(mod = "2pp",
                                    pars = pars.i.2pp,
                                    sub = ix.10,
                                    In = in.i,
                                    upper = c(1, 1, 0.951),
                                    lower = c(0, 0, 0.5))
names(mod.sens.fits.2pp.p3.5.95) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp.p3.5.95, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp.p3.5.95", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp.p3.5.95 <- lapply(mod.sens.fits.2pp.p3.5.95, function(x) x[[1]])

# 2pp3 (par range constraints, inputs fit to meas stocks)
mod.sens.fits.2pp3 <- mod.fits.fx(mod = "2pp",
                                  pars = pars.i.2pp,
                                  sub = ix.10,
                                  In = in.meas.2pp,
                                  upper = c(1, .02, .951),
                                  lower = c(.04, .0001, .5),
                                  cost = "14C only")
names(mod.sens.fits.2pp3) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp3, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp3", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp3 <- lapply(mod.sens.fits.2pp3, function(x) x[[1]])
# 2pp3s (par range constraints, inputs fit to meas stocks, + stock constraint)
mod.sens.fits.2pp3s <- mod.fits.fx(mod = "2pp",
                                   pars = pars.i.2pp,
                                   sub = ix.10,
                                   In = in.meas.2pp,
                                   upper = c(1, .02, .951),
                                   lower = c(.04, .0001, .5),
                                   cost = "cStock")
names(mod.sens.fits.2pp3s) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp3s, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp3s", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp3s <- lapply(mod.sens.fits.2pp3s, function(x) x[[1]])

## 2ps
# par range [0, 1] for all pars
mod.sens.fits.2ps <- mod.fits.fx(mod = "2ps",
                                 pars = pars.i.2ps, 
                                 sub = ix.10,
                                 In = in.i,
                                 upper = c(1, 1, 1),
                                 lower = c(0, 0, 0),
                                 cost = "14C")
names(mod.sens.fits.2ps) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps <- lapply(mod.sens.fits.2ps, function(x) x[[1]])
# 20-30
mod.sens.fits.2ps.30 <- mod.fits.fx(mod = "2ps",
                                    pars = pars.i.2ps, 
                                    sub = ix.30,
                                    In = in.i,
                                    upper = c(1, 1, 1),
                                    lower = c(0, 0, 0),
                                    cost = "14C")
names(mod.sens.fits.2ps.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.30 <- lapply(mod.sens.fits.2ps.30, function(x) x[[1]])

# 2ps3 (par range constraints, inputs fit to meas stocks)
mod.sens.fits.2ps3 <- mod.fits.fx(mod = "2ps",
                                  pars = pars.i.2ps,
                                  sub = ix.10,
                                  In = in.meas.2ps,
                                  upper = c(1, 1, .15),
                                  lower = c(0, 0, .0004),
                                  cost = "14C only")
names(mod.sens.fits.2ps3) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps3, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps3", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps3 <- lapply(mod.sens.fits.2ps3, function(x) x[[1]])
# 2ps3 (par range constraints, inputs fit to meas stocks, + stock constraint)
mod.sens.fits.2ps3s <- mod.fits.fx(mod = "2ps",
                                   pars = pars.i.2ps,
                                   sub = ix.10,
                                   In = in.meas.2ps,
                                   upper = c(1, .02, .1),
                                   lower = c(.04, .0001, 0),
                                   cost = "cStock")
names(mod.sens.fits.2ps3s) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps3s, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps3s", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps3s <- lapply(mod.sens.fits.2ps3s, function(x) x[[1]])

### 2p4 (par range set, stock and bulk 14C costs, GPP-based inputs by eco)
## 2pp
# 0-10
mod.sens.fits.2pp4.10 <- mod.fits.fx(mod = "2pp",
                                     pars = pars.i.2pp,
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .951),
                                     lower = c(.04, .0001, .5),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2pp4.10) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp4.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4.10 <- lapply(mod.sens.fits.2pp4.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2pp4.30 <- mod.fits.fx(mod = "2pp",
                                     pars = pars.i.2pp,
                                     sub = ix.30,
                                     In = in.est,
                                     upper = c(1, .02, .951),
                                     lower = c(.04, .0001, .5),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2pp4.30) <- names(pars.i.2pp)[ix.30]
save(mod.sens.fits.2pp4.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4.30 <- lapply(mod.sens.fits.2pp4.30, function(x) x[[1]])
## 2ps
# 0-10
mod.sens.fits.2ps4.10 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps,
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .1),
                                     lower = c(.04, .0001, 0),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2ps4.10) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps4.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4.10 <- lapply(mod.sens.fits.2ps4.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2ps4.30 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps,
                                     sub = ix.30,
                                     In = in.est,
                                     upper = c(1, .02, .1),
                                     lower = c(.04, .0001, 0),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2ps4.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps4.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4.30 <- lapply(mod.sens.fits.2ps4.30, function(x) x[[1]])

### 2p4r (par range set, stock, bulk, and respiration 14C costs, GPP-based inputs by eco)
## 2pp
# 0-10
mod.sens.fits.2pp4r.10 <- mod.fits.fx(mod = "2pp",
                                      pars = pars.i.2pp,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .951),
                                      lower = c(.04, .0001, .5),
                                      cost = "14C + cStock")
names(mod.sens.fits.2pp4r.10) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp4r.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4r.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4r.10 <- lapply(mod.sens.fits.2pp4r.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2pp4r.30 <- mod.fits.fx(mod = "2pp",
                                      pars = pars.i.2pp,
                                      sub = ix.30,
                                      In = in.est,
                                      upper = c(1, .02, .951),
                                      lower = c(.04, .0001, .5),
                                      cost = "14C + cStock")
names(mod.sens.fits.2pp4r.30) <- names(pars.i.2pp)[ix.30]
save(mod.sens.fits.2pp4r.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4r.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4r.30 <- lapply(mod.sens.fits.2pp4r.30, function(x) x[[1]])
## 2ps
# 0-10
mod.sens.fits.2ps4r.10 <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .1),
                                      lower = c(.04, .0001, 0),
                                      cost = "14C + cStock")
names(mod.sens.fits.2ps4r.10) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps4r.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4r.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4r.10 <- lapply(mod.sens.fits.2ps4r.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2ps4r.30 <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.30,
                                      In = in.est,
                                      upper = c(1, .02, .1),
                                      lower = c(.04, .0001, 0),
                                      cost = "14C + cStock")
names(mod.sens.fits.2ps4r.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps4r.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4r.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4r.30 <- lapply(mod.sens.fits.2ps4r.30, function(x) x[[1]])
# load initial parameters as needed
if (!exists("pars.i.2pp")) {
 load("../data/derived/modFit_pars/pars.i.2pp_2020-11-16.Rdata") 
}
if (!exists("pars.i.2ps")) {
  load("../data/derived/modFit_pars/pars.i.2ps_2020-11-16.Rdata")  
}

# load fits as needed
if (!exists("mod.fits.2pp")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp_2020-11-16.RData")
}
if (!exists("mod.fits.2pp.p3.5.95")) {
  load("../data/derived/modFit_pars/mod.fits.2pp.p3.5.95_2020-11-16.Rdata")  
}
if (!exists("mod.fits.2ps")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps_2020-11-16.Rdata")
}
if (!exists("mod.fits.2pp2")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp.flx.stock_2020-12-02.RData")
}
if (!exists("mod.fits.2ps2")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps.flx.stock_2020-12-02.Rdata")
}
if (!exists("mod.fits.2pp3")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp3_2020-12-08.RData")
}
if (!exists("mod.fits.2ps3")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps3_2020-12-08.Rdata")
}
if (!exists("mod.fits.2pp3s")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp3s_2020-12-08.RData")
}
if (!exists("mod.fits.2ps3s")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps3s_2020-12-08.Rdata")
}

## Par estimates
# 2pp
pars.fit.2pp <- lapply(mod.fits.2pp, "[[", 1)
names(pars.fit.2pp) <- names(pars.i.2pp)[ix.10]
# 2pp gam = [.5, .95]
pars.fit.2pp.p3.5.95 <- lapply(mod.fits.2pp.p3.5.95, "[[", 1)
names(pars.fit.2pp.p3.5.95) <- names(pars.i.2pp)[ix.10]

# 2ps
pars.fit.2ps <- lapply(mod.fits.2ps, "[[", 1)
names(pars.fit.2ps) <- names(pars.i.2ps)[ix.10]


# 2pp2 (input/stock and 14C constraints)
pars.fit.2pp2 <- lapply(mod.fits.2pp2, "[[", 1)
names(pars.fit.2pp2) <- names(pars.i.2pp)[ix.10]
# 2ps2 (input/stock and 14C constraints)
pars.fit.2ps2 <- lapply(mod.fits.2ps2, "[[", 1)
names(pars.fit.2ps2) <- names(pars.i.2ps)[ix.10]

# 2pp3 (14C constraints, constrained par ranges, stock-fit inputs)
pars.fit.2pp3 <- lapply(mod.fits.2pp3, "[[", 1)
names(pars.fit.2pp3) <- names(pars.i.2pp)[ix.10]
# 2ps3 (14C constraints, constrained par ranges, stock-fit inputs)
pars.fit.2ps3 <- lapply(mod.fits.2ps3, "[[", 1)
names(pars.fit.2ps3) <- names(pars.i.2ps)[ix.10]

# 2pp3s (14C constraints, constrained par ranges, stock-fit inputs, + stock constraint)
pars.fit.2pp3s <- lapply(mod.fits.2pp3s, "[[", 1)
names(pars.fit.2pp3s) <- names(pars.i.2pp)[ix.10]
# 2ps3s (14C constraints, constrained par ranges, stock-fit inputs, + stock constraint)
pars.fit.2ps3s <- lapply(mod.fits.2ps3s, "[[", 1)
names(pars.fit.2ps3s) <- names(pars.i.2ps)[ix.10]

## stock & bulk 14C costs only
# 2pp
pars.fit.2pp4.10 <- lapply(mod.fits.2pp4.10, "[[", 1)
names(pars.fit.2pp4.10) <- names(pars.i.2pp)[ix.10]
pars.fit.2pp4.30 <- lapply(mod.fits.2pp4.30, "[[", 1)
names(pars.fit.2pp4.30) <- names(pars.i.2pp)[ix.30]
# 2ps
pars.fit.2ps4.10 <- lapply(mod.fits.2ps4.10, "[[", 1)
names(pars.fit.2ps4.10) <- names(pars.i.2ps)[ix.10]
pars.fit.2ps4.30 <- lapply(mod.fits.2ps4.30, "[[", 1)
names(pars.fit.2ps4.30) <- names(pars.i.2ps)[ix.30]

## stock, bulk and respiration 14C costs
# 2pp
pars.fit.2pp4r.10 <- lapply(mod.fits.2pp4r.10, "[[", 1)
names(pars.fit.2pp4r.10) <- names(pars.i.2pp)[ix.10]
pars.fit.2pp4r.30 <- lapply(mod.fits.2pp4r.30, "[[", 1)
names(pars.fit.2pp4r.30) <- names(pars.i.2pp)[ix.30]
# 2ps
pars.fit.2ps4r.10 <- lapply(mod.fits.2ps4r.10, "[[", 1)
names(pars.fit.2ps4r.10) <- names(pars.i.2ps)[ix.10]
pars.fit.2ps4r.30 <- lapply(mod.fits.2ps4r.30, "[[", 1)
names(pars.fit.2ps4r.30) <- names(pars.i.2ps)[ix.30]

## Summary of fits
# 2pp
pars.fit.2pp.sum <- lapply(mod.fits.2pp, function(x) {
  tryCatch(summary(x), 
           error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(pars.fit.2pp.sum) <- names(pars.fit.2pp)
# 2ps
pars.fit.2ps.sum <- lapply(mod.fits.2ps, function(x) {
  tryCatch(summary(x), 
           error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(pars.fit.2ps.sum) <- names(pars.fit.2ps)

## Summary of errors
# best par set (ssr)
ssr.2pp.df <- data.frame(bind_rows(lapply(mod.fits.2pp, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps.df <- data.frame(bind_rows(lapply(mod.fits.2ps, "[", "ssr"), .id = "PMeco_depth"))
ssr.2pp2.df <- data.frame(bind_rows(lapply(mod.fits.2pp2, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps2.df <- data.frame(bind_rows(lapply(mod.fits.2ps2, "[", "ssr"), .id = "PMeco_depth"))
# stock and bulk 14C costs only
ssr.2pp4.10.df <- data.frame(bind_rows(lapply(mod.fits.2pp4.10, "[", "ssr"), .id = "PMeco_depth"))
ssr.2pp4.30.df <- data.frame(bind_rows(lapply(mod.fits.2pp4.30, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps4.10.df <- data.frame(bind_rows(lapply(mod.fits.2ps4.10, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps4.30.df <- data.frame(bind_rows(lapply(mod.fits.2ps4.30, "[", "ssr"), .id = "PMeco_depth"))
# stock, bulk and resp 14C costs
ssr.2pp4r.10.df <- data.frame(bind_rows(lapply(mod.fits.2pp4r.10, "[", "ssr"), .id = "PMeco_depth"))
ssr.2pp4r.30.df <- data.frame(bind_rows(lapply(mod.fits.2pp4r.30, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps4r.10.df <- data.frame(bind_rows(lapply(mod.fits.2ps4r.10, "[", "ssr"), .id = "PMeco_depth"))
ssr.2ps4r.30.df <- data.frame(bind_rows(lapply(mod.fits.2ps4r.30, "[", "ssr"), .id = "PMeco_depth"))

# mean residuals, by var (var_ms)
var_ms.df.fx <- function(mod.fits.ls, costs) {
  df <- data.frame(bind_rows(lapply(mod.fits.ls, "[", "var_ms"), .id = "PMeco_depth"))
  if (length(costs) == 2 ) {
    df$var <- rep(c("resp", "bulkC"), nrow(df)/2)
  } else {
    df$var <- rep(c("resp", "bulkC", "flx.stock"), nrow(df)/3)
  }
  df$var_ms <- round(df$var_ms, 5)
  return(df)
}
var_ms.2pp.df <- var_ms.df.fx(mod.fits.2pp, c("resp", "bulkC"))
var_ms.2pp.p3.5.95.df <- var_ms.df.fx(mod.fits.2pp.p3.5.95, c("resp", "bulkC"))
var_ms.2ps.df <- var_ms.df.fx(mod.fits.2ps, c("resp", "bulkC"))
var_ms.2pp2.df <- var_ms.df.fx(mod.fits.2pp2, c("resp", "bulkC", "flx.stock"))
var_ms.2ps2.df <- var_ms.df.fx(mod.fits.2ps2, c("resp", "bulkC", "flx.stock"))

# bind fitted pars with initial pars into data frame for plotting/summarizing
par.fit.df.fx <- function(mod, pars.fit, pars.i) {
  df <- bind_rows(
    lapply(
      mapply(rbind, 
             pars.fit,
             pars.i,
             SIMPLIFY = FALSE), 
      function(df) {
        df <- data.frame(df)
        if (mod == "2pp") {
          colnames(df) <- c("kfast", "kslow", "gam")
        } else {
          colnames(df) <- c("kfast", "kslow", "a21")
        }
        df$est <- c("fit", "init")
        return(df)
      })
  )
  df$PMeco_depth <- rep(names(pars.i), each = 2)
  df$PM <- substr(df$PMeco_depth, start = 1, stop = 2)
  df$eco <- substr(df$PMeco_depth, start = 3, stop = 4)
  df$depth <- substr(df$PMeco_depth, start = 6, stop = length(df$PMeco_depth))
  return(df)
}


## 2pp
# gam range = [0, 1]
pars.fit.2pp.df <- par.fit.df.fx(mod = "2pp",
                                 pars.fit = pars.fit.2pp,
                                 pars.i = pars.i.2pp[ix.10])
# gam range = [.5, .95]
pars.fit.2pp.p3.5.95.df <- par.fit.df.fx(mod = "2pp",
                                         pars.fit = pars.fit.2pp.p3.5.95,
                                         pars.i = pars.i.2pp[ix.10])
# w/ input/stock cost and gam range = [.5, .95]
pars.fit.2pp2.df <- par.fit.df.fx(mod = "2pp",
                                  pars.fit = pars.fit.2pp2,
                                  pars.i = pars.i.2pp[ix.10])

## 2ps
# a21 range = [0, 1]
pars.fit.2ps.df <- par.fit.df.fx(mod = "2ps",
                                 pars.fit = pars.fit.2ps,
                                 pars.i = pars.i.2ps[ix.10])
# w/ input/stock cost and a21 range = [0, 1]
pars.fit.2ps2.df <- par.fit.df.fx(mod = "2ps",
                                 pars.fit = pars.fit.2ps2,
                                 pars.i = pars.i.2ps[ix.10])

## Constrained par ranges, with and without stock constraint
# w/o stock
pars.fit.2pp3.df <- par.fit.df.fx(mod = "2pp",
                                  pars.fit = pars.fit.2pp3,
                                  pars.i = pars.i.2pp[ix.10])
pars.fit.2ps3.df <- par.fit.df.fx(mod = "2ps",
                                  pars.fit = pars.fit.2ps3,
                                  pars.i = pars.i.2ps[ix.10])
# w/ stock
pars.fit.2pp3s.df <- par.fit.df.fx(mod = "2pp",
                                   pars.fit = pars.fit.2pp3s,
                                   pars.i = pars.i.2ps[ix.10])
pars.fit.2ps3s.df <- par.fit.df.fx(mod = "2ps",
                                   pars.fit = pars.fit.2ps3s,
                                   pars.i = pars.i.2ps[ix.10])
# w/ stock & bulk 14C only
pars.fit.2pp4.10.df <- par.fit.df.fx(mod = "2pp",
                                     pars.fit = pars.fit.2pp4.10,
                                     pars.i = pars.i.2pp[ix.10])
pars.fit.2pp4.30.df <- par.fit.df.fx(mod = "2pp",
                                     pars.fit = pars.fit.2pp4.30,
                                     pars.i = pars.i.2pp[ix.30])
pars.fit.2ps4.10.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps4.10,
                                     pars.i = pars.i.2ps[ix.10])
pars.fit.2ps4.30.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps4.30,
                                     pars.i = pars.i.2ps[ix.30])

# w/ stock, bulk + resp 14C
pars.fit.2pp4r.10.df <- par.fit.df.fx(mod = "2pp",
                                     pars.fit = pars.fit.2pp4r.10,
                                     pars.i = pars.i.2pp[ix.10])
pars.fit.2pp4r.30.df <- par.fit.df.fx(mod = "2pp",
                                     pars.fit = pars.fit.2pp4r.30,
                                     pars.i = pars.i.2pp[ix.30])
pars.fit.2ps4r.10.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps4r.10,
                                     pars.i = pars.i.2ps[ix.10])
pars.fit.2ps4r.30.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps4r.30,
                                     pars.i = pars.i.2ps[ix.30])


## Summarize by PM, depth
# 2pp
# PM/depth
pars.fit.2pp.df.PM <- pars.fit.2pp.df %>%
    filter(est == "fit") %>%
    select(!c(est, PMeco_depth, eco)) %>%
    group_by(PM, depth) %>%
    summarize_all(list(mean = mean, sd = sd)) %>%
    mutate_if(is.numeric, format, digits = 2)
# print table
knitr::kable(pars.fit.2pp.df.PM,
             caption = "Mean parameter estimates by parent material (PM)",
             align = "c")
# eco/depth
pars.fit.2pp.df.eco <- pars.fit.2pp.df %>%
  filter(est == "fit") %>%
  mutate(eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  select(!c(est, PMeco_depth, PM)) %>%
  group_by(eco, depth) %>%
  summarize_all(list(mean = mean, sd = sd)) %>%
  mutate_if(is.numeric, format, digits = 2)
# print table
knitr::kable(pars.fit.2pp.df.eco,
             caption = "Mean parameter estimates by ecosystem (eco)",
             align = "c")
## look at sensFun output
# without constraints
sens.2pp <- lapply(mod.sens.fits.2pp, function(x) x[[2]])
sens.2ps <- lapply(mod.sens.fits.2ps, function(x) x[[2]])
# without stock constraint
sens.2pp3 <- lapply(mod.sens.fits.2pp3, function(x) x[[2]])
sens.2ps3 <- lapply(mod.sens.fits.2ps3, function(x) x[[2]])
# with stock constraint
sens.2pp3s <- lapply(mod.sens.fits.2pp3s, function(x) x[[2]])
sens.2ps3s <- lapply(mod.sens.fits.2ps3s, function(x) x[[2]])
# with stock constraint, w/o resp
sens.2pp4.10 <- lapply(mod.sens.fits.2pp4.10, function(x) x[[2]])
sens.2pp4.30 <- lapply(mod.sens.fits.2pp4.30, function(x) x[[2]])
sens.2ps4.10 <- lapply(mod.sens.fits.2ps4.10, function(x) x[[2]])
sens.2ps4.30 <- lapply(mod.sens.fits.2ps4.30, function(x) x[[2]])
# with stock constraint + resp
sens.2pp4r.10 <- lapply(mod.sens.fits.2pp4r.10, function(x) x[[2]])
sens.2pp4r.30 <- lapply(mod.sens.fits.2pp4r.30, function(x) x[[2]])
sens.2ps4r.10 <- lapply(mod.sens.fits.2ps4r.10, function(x) x[[2]])
sens.2ps4r.30 <- lapply(mod.sens.fits.2ps4r.30, function(x) x[[2]])


# plot sensitivity
# w/o constraints
lapply(sens.2pp, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps, function(x) plot(x, which = c("bulkC", "resp")))
# w/o stock constraint
lapply(sens.2pp3, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps3, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp3s, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps3s, function(x) plot(x, which = c("bulkC", "cStock")))
# with stock constraint, w/o resp
lapply(sens.2pp4.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp4.30, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4.30, function(x) plot(x, which = c("bulkC", "cStock")))
# with stock constraint + resp
lapply(sens.2pp4r.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp4r.30, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4r.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4r.30, function(x) plot(x, which = c("bulkC", "cStock")))


# look at identifiability
inden.df.fx <- function(ls, mod) {
  lapply(ls, function(x) {
    df <- collin(x)
    if (mod == "2pp") {
      df$ParCombo <- factor(c("k1 + k2", "k1 + gam", "k2 + gam", "k1 + k2 + gam"))
    } else {
      df$ParCombo <- factor(c("k1 + k2", "k1 + a21", "k2 + a21", "k1 + k2 + a21"))
    }
    return(df)
  })
}

iden.2pp <- inden.df.fx(sens.2pp, mod = "2pp")
iden.2ps <- inden.df.fx(sens.2ps, mod = "2ps")
iden.2pp3 <- inden.df.fx(sens.2pp3, mod = "2pp")
iden.2ps3 <- inden.df.fx(sens.2ps3, mod = "2ps")
iden.2pp3s <- inden.df.fx(sens.2pp3s, mod = "2pp")
iden.2ps3s <- inden.df.fx(sens.2ps3s, mod = "2ps")
# with stock constraint, w/o resp
iden.2pp4.10 <- inden.df.fx(sens.2pp4.10, mod = "2pp")
iden.2pp4.30 <- inden.df.fx(sens.2pp4.30, mod = "2pp")
iden.2ps4.10 <- inden.df.fx(sens.2ps4.10, mod = "2ps")
iden.2ps4.30 <- inden.df.fx(sens.2ps4.30, mod = "2ps")
# with stock constraint + resp
iden.2pp4r.10 <- inden.df.fx(sens.2pp4r.10, mod = "2pp")
iden.2pp4r.30 <- inden.df.fx(sens.2pp4r.30, mod = "2pp")
iden.2ps4r.10 <- inden.df.fx(sens.2ps4r.10, mod = "2ps")
iden.2ps4r.30 <- inden.df.fx(sens.2ps4r.30, mod = "2ps")

# identifiability plot function
coll.plot.fx <- function(df, mod, PMeco_depth, col.max) {
  ggplot(df, aes(N, log(collinearity), color = ParCombo)) +
    geom_hline(yintercept = log(20)) +
    geom_point(size = 3.5, position = position_dodge(width = .1)) +
    scale_y_continuous(limits = c(0, log(col.max))) +
    scale_x_continuous(limits = c(1.5, 3.5), breaks = c(2, 3)) +
    labs(title = paste(PMeco_depth, mod)) +
    theme_bw() +
    theme(panel.grid = element_blank()) +
    if (mod == "2pp" | mod == "2pp + stock") {
     scale_color_manual(
       name = "Parameter combination",
       values = c("k1 + k2" = "#EF476F",
                  "k1 + gam" = "#FFD166",
                  "k2 + gam" = "#118AB2",
                  "k1 + k2 + gam" = "073B4C")) 
    } else {
      scale_color_manual(
        name = "Parameter combination",
        values = c("k1 + k2" = "#EF476F",
                  "k1 + a21" = "#FFD166",
                  "k2 + a21" = "#118AB2",
                  "k1 + k2 + a21" = "073B4C"))
    }
}
lapply(seq_along(iden.2pp), function(i) {
  coll.plot.fx(iden.2pp[[i]], mod = "2pp", names(iden.2pp)[i], max(iden.2pp[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps), function(i) {
  coll.plot.fx(iden.2ps[[i]], mod = "2ps", names(iden.2ps)[i], max(iden.2ps[[i]]["collinearity"]))
})
lapply(seq_along(iden.2pp3), function(i) {
  coll.plot.fx(iden.2pp3[[i]], mod = "2pp", names(iden.2pp3)[i])
})
lapply(seq_along(iden.2pp3s), function(i) {
  coll.plot.fx(iden.2pp3s[[i]], mod = "2pp + stock", names(iden.2pp3s)[i])
})
lapply(seq_along(iden.2ps3), function(i) {
  coll.plot.fx(iden.2ps3[[i]], mod = "2ps", names(iden.2ps3)[i])
})
lapply(seq_along(iden.2ps3s), function(i) {
  coll.plot.fx(iden.2ps3s[[i]], mod = "2ps + stock", names(iden.2ps3s)[i])
})
# stock constraint, w/o resp
col.max <- max(unlist(list(lapply(iden.2ps4.10, function(df) df[["collinearity"]]),
                           lapply(iden.2ps4.30, function(df) df[["collinearity"]]),
                           lapply(iden.2pp4.10, function(df) df[["collinearity"]]),
                           lapply(iden.2pp4.30, function(df) df[["collinearity"]]))))
lapply(seq_along(iden.2ps4.10), function(i) {
  coll.plot.fx(iden.2ps4.10[[i]], mod = "2ps + stock", names(iden.2ps4.10)[i], col.max)
})
lapply(seq_along(iden.2ps4.30), function(i) {
  coll.plot.fx(iden.2ps4.30[[i]], mod = "2ps + stock", names(iden.2ps4.30)[i], col.max)
})
lapply(seq_along(iden.2pp4.10), function(i) {
  coll.plot.fx(iden.2pp4.10[[i]], mod = "2pp + stock", names(iden.2pp4.10)[i], col.max)
})
lapply(seq_along(iden.2pp4.30), function(i) {
  coll.plot.fx(iden.2pp4.30[[i]], mod = "2pp + stock", names(iden.2pp4.30)[i], col.max)
})

# stock constraint + resp
col.max.r <- max(unlist(list(lapply(iden.2ps4r.10, function(df) df[["collinearity"]]),
                             lapply(iden.2ps4r.30, function(df) df[["collinearity"]]),
                             lapply(iden.2pp4r.10, function(df) df[["collinearity"]]),
                             lapply(iden.2pp4r.30, function(df) df[["collinearity"]]))))
lapply(seq_along(iden.2pp4r.10), function(i) {
  coll.plot.fx(iden.2pp4r.10[[i]], mod = "2pp", names(iden.2pp4r.10)[i], col.max)
})
lapply(seq_along(iden.2pp4r.30), function(i) {
  coll.plot.fx(iden.2pp4r.30[[i]], mod = "2ps", names(iden.2pp4r.30)[i], col.max)
})
lapply(seq_along(iden.2ps4r.10), function(i) {
  coll.plot.fx(iden.2ps4r.10[[i]], mod = "2ps + stock", names(iden.2ps4r.10)[i], col.max)
})
lapply(seq_along(iden.2ps4r.30), function(i) {
  coll.plot.fx(iden.2ps4r.30[[i]], mod = "2ps + stock", names(iden.2ps4r.30)[i], col.max)
})
## plot pars
par.plot.fx <- function(mod, depth, par.df, initial = FALSE) {
  par.df %>%
    { if (initial == TRUE) . else filter(., est == "fit") } %>%
    filter(depth == depth) %>%
    pivot_longer(!(est:depth), names_to = "par", values_to = "value") %>%
    mutate(PM = factor(PM),
           eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
    ggplot(., aes(par, value, color = PM, shape = eco)) +
    # geom_jitter(size = 4) +
    geom_point(size = 4, position = position_dodge(width = .5)) +
    scale_color_manual(name = "parent material",
                      labels = c("AN" = "andesite",
                                 "BS" = "basalt",
                                 "GR" = "granite"),
                      values = c("AN" = "blue", 
                                 "BS" = "red", 
                                 "GR" = "darkgray")) +
    facet_wrap(. ~ par, scales = "free") +
    ggtitle(paste0("modFit pars ", mod, " ", depth)) +
    theme_bw() +
    theme(panel.grid.minor = element_blank())
}
# 0-10
# 2pp
par.plot.fx(mod = "2pp",
            depth = "0-10",
            par.df = pars.fit.2pp.df,
            initial = FALSE)
# 2pp, gam = [.5,.95]
par.plot.fx(mod = "2pp (gam = [0.5, 0.95])",
            depth = "0-10",
            par.df = pars.fit.2pp.p3.5.95.df,
            initial = FALSE)
# 2pp2
par.plot.fx(mod = "2pp2",
            depth = "0-10",
            par.df = pars.fit.2pp2.df,
            initial = FALSE)
# 2ps
par.plot.fx(mod = "2ps",
            depth = "0-10",
            par.df = pars.fit.2ps.df,
            initial = FALSE)
# 2ps2
par.plot.fx(mod = "2ps2",
            depth = "0-10",
            par.df = pars.fit.2ps2.df,
            initial = FALSE)

# w/ and w/o stock constraint
par.plot.fx(mod = "2pp3",
            depth = "0-10",
            par.df = pars.fit.2pp3.df,
            initial = FALSE)
par.plot.fx(mod = "2pp3s",
            depth = "0-10",
            par.df = pars.fit.2pp3s.df,
            initial = FALSE)
par.plot.fx(mod = "2ps3",
            depth = "0-10",
            par.df = pars.fit.2ps3.df,
            initial = FALSE)
par.plot.fx(mod = "2ps3s",
            depth = "0-10",
            par.df = pars.fit.2ps3s.df,
            initial = FALSE)

## flux est inputs by eco
# stock and bulk 14C only
par.plot.fx(mod = "2pp4",
            depth = "0-10",
            par.df = pars.fit.2pp4.10.df,
            initial = FALSE)
par.plot.fx(mod = "2pp4",
            depth = "20-30",
            par.df = pars.fit.2pp4.30.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4",
            depth = "0-10",
            par.df = pars.fit.2ps4.10.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4",
            depth = "20-30",
            par.df = pars.fit.2ps4.30.df,
            initial = FALSE)

# stock and bulk + resp 14C
par.plot.fx(mod = "2pp4r",
            depth = "0-10",
            par.df = pars.fit.2pp4r.10.df,
            initial = FALSE)
par.plot.fx(mod = "2pp4r",
            depth = "20-30",
            par.df = pars.fit.2pp4r.30.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4r",
            depth = "0-10",
            par.df = pars.fit.2ps4r.10.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4r",
            depth = "20-30",
            par.df = pars.fit.2ps4r.30.df,
            initial = FALSE)
## Find best inputs
# 2pp
in.fit.2pp <- lapply(seq_along(pars.fit.2pp), function(i) {
  PMeco_depth <- names(pars.fit.2pp)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2pp) <- names(mod.fits.2pp)
# 2pp gam = [.5, .95]
in.fit.2pp.p3.5.95 <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  PMeco_depth <- names(pars.fit.2pp.p3.5.95)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp.p3.5.95[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2pp.p3.5.95) <- names(mod.fits.2pp.p3.5.95)
# 2pp2
in.fit.2pp2 <- lapply(seq_along(pars.fit.2pp2), function(i) {
  PMeco_depth <- names(pars.fit.2pp2)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp2[[i]], in.flx.stock[[i]], SOC))
})
names(in.fit.2pp2) <- names(mod.fits.2pp2)
# 2ps
in.fit.2ps <- lapply(seq_along(pars.fit.2ps), function(i) {
  PMeco_depth <- names(pars.fit.2ps)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2ps", pars.fit.2ps[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2ps) <- names(mod.fits.2ps)
# 2ps2
in.fit.2ps2 <- lapply(seq_along(pars.fit.2ps2), function(i) {
  PMeco_depth <- names(pars.fit.2ps2)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2ps", pars.fit.2ps2[[i]], in.flx.stock[[i]], SOC))
})
names(in.fit.2ps2) <- names(mod.fits.2ps2)

## Calc modeled stocks and compare with measured stocks
# 2pp
mod.socs.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  soc.fx("2pp", pars.fit.2pp[[i]], in.fit.2pp[[i]])
})
names(mod.socs.2pp.ls) <- names(pars.fit.2pp)
socs.2pp.ls <- mapply(cbind,
                      csoc.19.0_30[ix.10], 
                      lapply(mod.socs.2pp.ls, colSums), 
                      SIMPLIFY = FALSE)
# 2pp gam = [.5, .95]
mod.socs.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  soc.fx("2pp", pars.fit.2pp.p3.5.95[[i]], in.fit.2pp.p3.5.95[[i]])
})
names(mod.socs.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
socs.2pp.p3.5.95ls <- mapply(cbind,
                             csoc.19.0_30[ix.10], 
                             lapply(mod.socs.2pp.p3.5.95.ls, colSums), 
                             SIMPLIFY = FALSE)
# 2pp2
mod.socs.2pp2.ls <- lapply(seq_along(pars.fit.2pp2), function(i) {
  soc.fx("2pp", pars.fit.2pp2[[i]], in.fit.2pp2[[i]])
})
names(mod.socs.2pp2.ls) <- names(pars.fit.2pp2)

# 2ps
mod.socs.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  soc.fx("2ps", pars.fit.2ps[[i]], in.fit.2ps[[i]])
})
names(mod.socs.2ps.ls) <- names(pars.fit.2ps)
socs.2ps.ls <- mapply(cbind,
                      csoc.19.0_30[ix.10], 
                      lapply(mod.socs.2ps.ls, colSums), 
                      SIMPLIFY = FALSE)
# 2ps2
mod.socs.2ps2.ls <- lapply(seq_along(pars.fit.2ps2), function(i) {
  soc.fx("2ps", pars.fit.2ps2[[i]], in.fit.2ps2[[i]])
})
names(mod.socs.2ps2.ls) <- names(pars.fit.2ps2)

## stock and bulk 14C costs only
# 2pp
mod.socs.2pp4.10.ls <- lapply(seq_along(pars.fit.2pp4.10), function(i) {
  soc.fx("2pp", pars.fit.2pp4.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2pp4.10.ls) <- names(pars.fit.2pp4.10)
mod.socs.2pp4.30.ls <- lapply(seq_along(pars.fit.2pp4.30), function(i) {
  soc.fx("2pp", pars.fit.2pp4.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2pp4.30.ls) <- names(pars.fit.2pp4.30)
# 2ps
mod.socs.2ps4.10.ls <- lapply(seq_along(pars.fit.2ps4.10), function(i) {
  soc.fx("2ps", pars.fit.2ps4.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2ps4.10.ls) <- names(pars.fit.2ps4.10)
mod.socs.2ps4.30.ls <- lapply(seq_along(pars.fit.2ps4.30), function(i) {
  soc.fx("2ps", pars.fit.2ps4.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2ps4.30.ls) <- names(pars.fit.2ps4.30)

## stock and bulk + resp 14C costs
# 2pp
mod.socs.2pp4r.10.ls <- lapply(seq_along(pars.fit.2pp4r.10), function(i) {
  soc.fx("2pp", pars.fit.2pp4r.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2pp4r.10.ls) <- names(pars.fit.2pp4r.10)
mod.socs.2pp4r.30.ls <- lapply(seq_along(pars.fit.2pp4r.30), function(i) {
  soc.fx("2pp", pars.fit.2pp4r.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2pp4r.30.ls) <- names(pars.fit.2pp4r.30)
# 2ps
mod.socs.2ps4r.10.ls <- lapply(seq_along(pars.fit.2ps4r.10), function(i) {
  soc.fx("2ps", pars.fit.2ps4r.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2ps4r.10.ls) <- names(pars.fit.2ps4r.10)
mod.socs.2ps4r.30.ls <- lapply(seq_along(pars.fit.2ps4r.30), function(i) {
  soc.fx("2ps", pars.fit.2ps4r.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2ps4r.30.ls) <- names(pars.fit.2ps4r.30)


## Return data frames of model fits with adjusted inputs and optimal parameters
# 2pp
Twopp.fits <- lapply(seq_along(pars.fit.2pp), function(i) {
  par.fx(pars.fit.2pp[[i]], in.fit.2pp[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp.fits) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
Twopp.p3.5.95.fits <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  par.fx(pars.fit.2pp.p3.5.95[[i]], in.fit.2pp.p3.5.95[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp.p3.5.95.fits) <- names(pars.fit.2pp.p3.5.95)
# 2pp2
Twopp2.fits <- lapply(seq_along(pars.fit.2pp2), function(i) {
  par.fx(pars.fit.2pp2[[i]], in.fit.2pp2[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp2.fits) <- names(pars.fit.2pp2)
# 2ps
Twops.fits <- lapply(seq_along(pars.fit.2ps), function(i) {
  par.fx(pars.fit.2ps[[i]], in.fit.2ps[[i]], verbose = FALSE, mod = "2ps")
})
names(Twops.fits) <- names(pars.fit.2ps)
# 2ps2
Twops2.fits <- lapply(seq_along(pars.fit.2ps2), function(i) {
  par.fx(pars.fit.2ps2[[i]], in.fit.2ps2[[i]], verbose = FALSE, mod = "2ps", pass = TRUE)
})
names(Twops2.fits) <- names(pars.fit.2ps2)

## stock and bulk 14C costs only
# 2pp
Twopp4.10.fits <- lapply(seq_along(pars.fit.2pp4.10), function(i) {
  par.fx(pars.fit.2pp4.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4.10.fits) <- names(pars.fit.2pp4.10)
Twopp4.30.fits <- lapply(seq_along(pars.fit.2pp4.30), function(i) {
  par.fx(pars.fit.2pp4.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4.30.fits) <- names(pars.fit.2pp4.30)
# 2ps
Twops4.10.fits <- lapply(seq_along(pars.fit.2ps4.10), function(i) {
  par.fx(pars.fit.2ps4.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4.10.fits) <- names(pars.fit.2ps4.10)
Twops4.30.fits <- lapply(seq_along(pars.fit.2ps4.30), function(i) {
  par.fx(pars.fit.2ps4.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4.30.fits) <- names(pars.fit.2ps4.30)

## stock and bulk + resp 14C costs
# 2pp
Twopp4r.10.fits <- lapply(seq_along(pars.fit.2pp4r.10), function(i) {
  par.fx(pars.fit.2pp4r.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4r.10.fits) <- names(pars.fit.2pp4r.10)
Twopp4r.30.fits <- lapply(seq_along(pars.fit.2pp4r.30), function(i) {
  par.fx(pars.fit.2pp4r.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4r.30.fits) <- names(pars.fit.2pp4r.30)
# 2ps
Twops4r.10.fits <- lapply(seq_along(pars.fit.2ps4r.10), function(i) {
  par.fx(pars.fit.2ps4r.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4r.10.fits) <- names(pars.fit.2ps4r.10)
Twops4r.30.fits <- lapply(seq_along(pars.fit.2ps4r.30), function(i) {
  par.fx(pars.fit.2ps4r.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4r.30.fits) <- names(pars.fit.2ps4r.30)
# Plot optimized model SOC stocks
mod.socs.df.fx <- function(mod, mod.socs.ls, pools) {
  n <- vapply(mod.socs.ls, nrow, numeric(1))
  return(data.frame(SOC = do.call(rbind, mod.socs.ls),
                    pool = rep(pools, length(mod.socs.ls)),
                    PMeco_depth = rep(names(mod.socs.ls), n),
                    Model = rep(mod, sum(n))))       
}
# run fx
# mod.socs.2p.df <- rbind(mod.socs.df.fx("2pp", mod.socs.2pp.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2ps", mod.socs.2ps.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2pp [.5,.95]", mod.socs.2pp.p3.5.95.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2ps2", mod.socs.2ps2.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2pp2", mod.socs.2pp2.ls, c("fast", "slow"))
#                         )
mod.socs.2p.df <- rbind(mod.socs.df.fx("2pp", mod.socs.2pp.ls, c("fast", "slow"))
                        ,mod.socs.df.fx("2ps", mod.socs.2ps.ls, c("fast", "slow"))
                        )


# stocks and bulk 14C only
mod.socs.2p4.10.df <- rbind(mod.socs.df.fx("2pp4 0-10", mod.socs.2pp4.10.ls, c("fast", "slow")), mod.socs.df.fx("2ps4 0-10", mod.socs.2ps4.10.ls, c("fast", "slow")))
mod.socs.2p4.30.df <- rbind(mod.socs.df.fx("2pp4 20-30", mod.socs.2pp4.30.ls, c("fast", "slow")) ,mod.socs.df.fx("2ps4 20-30", mod.socs.2ps4.30.ls, c("fast", "slow")))

# stocks and bulk + resp 14C
mod.socs.2p4r.10.df <- rbind(mod.socs.df.fx("2pp4r 0-10", mod.socs.2pp4r.10.ls, c("fast", "slow")), mod.socs.df.fx("2ps4r 0-10", mod.socs.2ps4r.10.ls, c("fast", "slow")))
mod.socs.2p4r.30.df <- rbind(mod.socs.df.fx("2pp4r 20-30", mod.socs.2pp4r.30.ls, c("fast", "slow")) ,mod.socs.df.fx("2ps4r 20-30", mod.socs.2ps4r.30.ls, c("fast", "slow")))

# combine inputs to compare
# in.fits.df <- pivot_longer(do.call(bind_rows, list(in.fit.2pp,
#                                                 in.fit.2pp.p3.5.95,
#                                                 in.fit.2pp2,
#                                                 in.fit.2ps,
#                                                 in.fit.2ps2)),
#                            everything(),
#                            names_to = "PMeco_depth",
#                            values_to = "inputs")
# in.fits.df$mod <- rep(c("2pp",
#                         "2pp.5.95",
#                         "2pp2",
#                         "2ps",
#                         "2ps2"),
#                       each = 9)
in.fits.df <- pivot_longer(do.call(bind_rows, list(in.fit.2pp,
                                                   in.fit.2ps)),
                           everything(),
                           names_to = "PMeco_depth",
                           values_to = "inputs")
in.fits.df$mod <- rep(c("2pp",
                        "2ps"),
                      each = 9)
                        
## plot stocks
# stock and bulk 14C only
mod.socs.2p4.10.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2p4.30.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# stock and bulk + resp 14C
mod.socs.2p4r.10.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2p4r.30.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# inputs
in.fits.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         # Model = factor(Model, levels = c("2pp [.5,.95]", "2pp", "2ps")),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(mod, inputs, fill = mod)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# plot fx
Twop.fit.plot.fx <- function(fit1, fit1.name, fit2, fit2.name, fit3 = NULL, fit3.name = NULL) {
  lapply(seq_along(fit1), function(i) {
    PMeco <- substr(names(fit1)[i], 1, 4)
    lyr_bot <- substr(names(fit1)[i], 
                      nchar(names(fit1)[i]) - 1, 
                      nchar(names(fit1)[i]))
    lyr_top <- ifelse(lyr_bot == 10, 0, ifelse(lyr_bot == 20, 10, 20))
    PMeco_depth <- names(fit1)[i]
    con.df <- con.df.fx(PMeco_depth)
    plot.df <- rbind(fit1[[i]],
                     fit2[[i]],
                     fit3[[i]])
    plot.df$Model <- factor(c(rep(fit1.name, nrow(fit1[[i]])),
                              rep(fit2.name, nrow(fit2[[i]])),
                              rep(fit3.name, nrow(fit3[[i]]))),
                            levels = c(fit1.name, fit2.name, fit3.name))
    return(plot.df %>%
             filter(pool == "bulk C" | pool == "respiration" | pool == "atm") %>%
             ggplot(., aes(years, d14C, color = pool)) +
             geom_path(aes(linetype = Model)) +
             geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
             scale_color_manual(
               name = "Model pool",
               values = c("atm" = 8,
                          "bulk C" = "black",
                          "fast" = "#D81B60",
                          "slow" = "#1E88E5",
                          "respiration" = "#FFC107")) +
             scale_x_continuous(limits = c(1950, 2022)) +
             ggtitle(paste0(PMeco_depth, " 2p mod fits")) +
             xlab("Year") +
             ylab(expression(''*Delta*''^14*'C (‰)')) +
             theme_bw() +
             theme(panel.grid = element_blank()))
  })
}
# 2p modFit optimal model comparison
Twop.fits.plots <- Twop.fit.plot.fx(Twopp.fits, "2pp", Twops.fits, "2ps")
Twop.fits.plots
# Twop.fits.plots2 <- Twop.fit.plot.fx(Twopp.fits, "2pp", Twopp.p3.5.95.fits, "2pp gam = [.5, .95]")
# Twop.fits.plots2
Twop.fits.plots3 <- Twop.fit.plot.fx(Twopp.p3.5.95.fits, "2pp gam = [.5, .95]", Twopp2.fits, "2pp2")
Twop.fits.plots3

## compare fits w/ and w/o resp constraint (2p4 mods)
# 2pp
Twopp4.fits.plots.10 <- Twop.fit.plot.fx(Twopp4.10.fits, "2pp4 0-10cm w/o resp", Twopp4r.10.fits, "2pp4r 0-10cm w/ resp")
Twopp4.fits.plots.30 <- Twop.fit.plot.fx(Twopp4.30.fits, "2pp4 20-30cm w/o resp", Twopp4r.10.fits, "2pp4r 20-30cm w/ resp")
# 2ps
Twops4.fits.plots.10 <- Twop.fit.plot.fx(Twops4.10.fits, "2ps4 0-10cm w/o resp", Twops4r.10.fits, "2ps4r 0-10cm w/ resp")
Twops4.fits.plots.30 <- Twop.fit.plot.fx(Twops4.30.fits, "2ps4 20-30cm w/o resp", Twops4r.10.fits, "2ps4r 20-30cm w/ resp")
# plot
Twopp4.fits.plots.10
Twopp4.fits.plots.30
Twops4.fits.plots.10
Twops4.fits.plots.30
p <- sra.ts.all %>%
    filter(d14c > -200) %>%
    filter(ECO != "rf") %>%
    filter(lyr_bot == 20) %>%
    filter(year != 2009) %>%
    ggplot(., aes(year, d14c)) +
    geom_path(data = atm.14c) +
    geom_point(aes(color = pm, shape = ecoType), size = 3.5) +
    geom_path(aes(color = pm, linetype = Type), size = 1, alpha = 0.3) +
    geom_errorbar(
        aes(ymin = d14c_l, 
            ymax = d14c_u,
            color = pm), 
        width = .5) +
    scale_color_manual(name = "Parent material",
                       values = c("andesite" = "blue", 
                                  "basalt" = "red", 
                                  "granite" = "darkgray")) +
    scale_shape_manual(name = "Ecosystem (type)",
                       values = c("warm (inc)" = 0,
                                  "cool (inc)" = 1,
                                  "cold (inc)" = 2,
                                  "warm (bulk)" = 15,
                                  "cool (bulk)" = 16,
                                  "cold (bulk)" = 17)) +
    facet_grid(rows = vars(eco), cols = vars(pm)) +
    ylab(expression(Delta*''^14*'C (‰)')) +
    xlab("Year") +
    ggtitle("Bulk/inc 10-20 cm") +
    theme_bw() +
    theme(panel.grid = element_blank(),
          axis.text.x = element_text(size = 8))
ggsave("sra.ts.ppwf20.blk.inc.pdf", p, dpi = 300, width = 6.97, height = 5, units = "in")
# inc/bulk profiles
p <- sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  select(Year, PM, ECO, PMeco, lyr_bot, d14c, d14c_sd) %>%
  mutate(Type = "bulk",
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         year = as.numeric(as.character(Year))) %>%
  select(-d14c_sd) %>%
  bind_rows(.,
            sra.19.01.inc %>%
              select(year, PM, ECO, PMeco, lyr_bot, d14c, d14c_min, d14c_max) %>%
              rename(d14c_l = d14c_min,
                     d14c_u = d14c_max) %>%
              mutate(Type = "inc")
  ) %>%
  mutate(depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         ecoType = paste0(eco, " (", Type, ")"))
ggsave("sra.ts.ppwf20.blk.pdf", p, dpi = 300, width = 6.97, height = 5, units = "in")
### Run modfit
## 14C bulk only
# 0-10
mod.sens.fits.2ps.10b <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .999),
                                     lower = c(.02, .0001, .001),
                                     cost = "14C bulk only")
names(mod.sens.fits.2ps.10b) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10b", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])

## 14C (bulk + resp)
# 0-10
mod.sens.fits.2ps.10br <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .999),
                                     lower = c(.02, .0001, .001),
                                     cost = "14C")
names(mod.sens.fits.2ps.10br) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10br, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10br", "_", Sys.Date(), ".Rdata"))
# 10-20, lag = 5
mod.sens.fits.2ps.20br.l <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                      lag = 5,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C")
names(mod.sens.fits.2ps.20br.l) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20br.l, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20br.l", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30br <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C")
# names(mod.sens.fits.2ps.30br) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30br, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30br", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30br <- lapply(mod.sens.fits.2ps.30br, function(x) x[[1]])

## 14C bulk + stocks
# 0-10
mod.sens.fits.2ps.10bs <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .999),
                                      lower = c(.02, .0001, .001),
                                      cost = "14C bulk + cStock")
names(mod.sens.fits.2ps.10bs) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10bs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10bs", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[1]])
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])

## 14C + cStock (14C resp, 14C bulk, stocks)
# 0-10
mod.sens.fits.2ps.10rbs <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.10,
                                       In = in.est,
                                       upper = c(1, .02, .999),
                                       lower = c(.02, .0001, .001),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.10rbs) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10rbs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10rbs", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[1]])
# 10-20
# w/o lag
mod.sens.fits.2ps.20rbs <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.20rbs) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20rbs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20rbs", "_", Sys.Date(), ".Rdata"))
# w/ lag = 12
mod.sens.fits.2ps.20rbs.l <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                       lag = 12,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.20rbs.l) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20rbs.l, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20rbs.l", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])
# SAB fits
load("../data/derived/modFit_pars/mod.fits.2ps.10b_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10br_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10bs_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10rbs_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20rbs_2021-04-12.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20rbs.l_2021-04-13.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20br.l_2021-04-13.Rdata")
load("../data/derived/modFit_pars/pars.i.2ps_2021-04-06.Rdata")

# extract mod fits
mod.fits.2ps.10b <- lapply(mod.sens.fits.2ps.10b, function(x) x[[1]])
mod.fits.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[1]])
mod.fits.2ps.10br <- lapply(mod.sens.fits.2ps.10br, function(x) x[[1]])
mod.fits.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[1]])
mod.fits.2ps.20rbs <- lapply(mod.sens.fits.2ps.20rbs, function(x) x[[1]])
mod.fits.2ps.20rbs.l <- lapply(mod.sens.fits.2ps.20rbs.l, function(x) x[[1]])
mod.fits.2ps.20br.l <- lapply(mod.sens.fits.2ps.20br.l, function(x) x[[1]]) 
  
# Sensitivity/Identifiability
#####
# extract at sensFun output
sens.2ps.10b <- lapply(mod.sens.fits.2ps.10b, function(x) x[[2]])
sens.2ps.10br <- lapply(mod.sens.fits.2ps.10br, function(x) x[[2]])
sens.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[2]])
sens.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[2]])
sens.2ps.20rbs <- lapply(mod.sens.fits.2ps.20rbs, function(x) x[[2]])
sens.2ps.20rbs.l <- lapply(mod.sens.fits.2ps.20rbs.l, function(x) x[[2]])
sens.2ps.20br.l <- lapply(mod.sens.fits.2ps.20br.l, function(x) x[[2]])

# plot sensitivity
lapply(sens.2ps.10b, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10br, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10bs, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10rbs, function(x) plot(x, which = c("bulkC", "resp")))

# look at identifiability
iden.2ps.10b <- inden.df.fx(sens.2ps.10b, mod = "2ps")
iden.2ps.10br <- inden.df.fx(sens.2ps.10br, mod = "2ps")
iden.2ps.10bs <- inden.df.fx(sens.2ps.10bs, mod = "2ps")
iden.2ps.10rbs <- inden.df.fx(sens.2ps.10rbs, mod = "2ps")
iden.2ps.20rbs <- inden.df.fx(sens.2ps.20rbs, mod = "2ps")
iden.2ps.20rbs.l <- inden.df.fx(sens.2ps.20rbs.l, mod = "2ps")
iden.2ps.20br.l <- inden.df.fx(sens.2ps.20br.l, mod = "2ps")

# plot
lapply(seq_along(iden.2ps.10bs), function(i) {
  coll.plot.fx(iden.2ps.10bs[[i]], mod = "2ps", 
               names(iden.2ps.10bs)[i], 
               max(iden.2ps.10bs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.10br), function(i) {
  coll.plot.fx(iden.2ps.10br[[i]], mod = "2ps", 
               names(iden.2ps.10br)[i], 
               max(iden.2ps.10br[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.10rbs), function(i) {
  coll.plot.fx(iden.2ps.10rbs[[i]], mod = "2ps", 
               names(iden.2ps.10rbs)[i], 
               max(iden.2ps.10rbs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20rbs), function(i) {
  coll.plot.fx(iden.2ps.20rbs[[i]], mod = "2ps", 
               names(iden.2ps.20rbs)[i], 
               max(iden.2ps.20rbs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20rbs.l), function(i) {
  coll.plot.fx(iden.2ps.20rbs.l[[i]], mod = "2ps", 
               names(iden.2ps.20rbs.l)[i], 
               max(iden.2ps.20rbs.l[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20br.l), function(i) {
  coll.plot.fx(iden.2ps.20br.l[[i]], mod = "2ps", 
               names(iden.2ps.20br.l)[i], 
               max(iden.2ps.20br.l[[i]]["collinearity"]))
})
#####

# Extract optimized pars from modfit output
#####
## bulk 14c only
# 0-10
pars.fit.2ps.10b <- lapply(mod.fits.2ps.10b, "[[", 1)
names(pars.fit.2ps.10b) <- names(pars.i.2ps)[ix.10]
# # 20-30
# pars.fit.2ps.30b <- lapply(mod.fits.2ps.30b, "[[", 1)
# names(pars.fit.2ps.30b) <- names(pars.i.2ps)[ix.30]

## resp + bulk 14c
# 0-10
pars.fit.2ps.10br <- lapply(mod.fits.2ps.10br, "[[", 1)
names(pars.fit.2ps.10br) <- names(pars.i.2ps)[ix.10]
# 10-20 w/ lag = 5y
pars.fit.2ps.20br.l <- lapply(mod.fits.2ps.20br.l, "[[", 1)
names(pars.fit.2ps.20br.l) <- names(pars.i.2ps)[ix.20]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]

## bulk 14c + stocks
# 0-10
pars.fit.2ps.10bs <- lapply(mod.fits.2ps.10bs, "[[", 1)
names(pars.fit.2ps.10bs) <- names(pars.i.2ps)[ix.10]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]

## resp, bulk 14c, stocks
# 0-10
pars.fit.2ps.10rbs <- lapply(mod.fits.2ps.10rbs, "[[", 1)
names(pars.fit.2ps.10rbs) <- names(pars.i.2ps)[ix.10]
# 10-20
pars.fit.2ps.20rbs <- lapply(mod.fits.2ps.20rbs, "[[", 1)
names(pars.fit.2ps.20rbs) <- names(pars.i.2ps)[ix.20]
# 10-20 w/ lag = 12y
pars.fit.2ps.20rbs.l <- lapply(mod.fits.2ps.20rbs.l, "[[", 1)
names(pars.fit.2ps.20rbs.l) <- names(pars.i.2ps)[ix.20]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]
#####

# SOC stocks
#####
# w/o stock constraint
mod.socs.2ps.10b.ls <- lapply(seq_along(pars.fit.2ps.10b), function(i) {
  soc.fx("2ps", pars.fit.2ps.10b[[i]], in.est[[i]])
})
names(mod.socs.2ps.10b.ls) <- names(pars.fit.2ps.10b)
mod.socs.2ps.10br.ls <- lapply(seq_along(pars.fit.2ps.10br), function(i) {
  soc.fx("2ps", pars.fit.2ps.10br[[i]], in.est[[i]])
})
names(mod.socs.2ps.10br.ls) <- names(pars.fit.2ps.10br)
socs.2ps.10br.ls <- mapply(cbind,
                           csoc.19.0_30[ix.10], 
                           lapply(mod.socs.2ps.10br.ls, colSums), 
                           SIMPLIFY = FALSE)
# w/ stock constraint
mod.socs.2ps.10bs.ls <- lapply(seq_along(pars.fit.2ps.10bs), function(i) {
  soc.fx("2ps", pars.fit.2ps.10bs[[i]], in.est[[i]])
})
names(mod.socs.2ps.10bs.ls) <- names(pars.fit.2ps.10bs)
mod.socs.2ps.10rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  soc.fx("2ps", pars.fit.2ps.10rbs[[i]], in.est[[i]])
})
names(mod.socs.2ps.10rbs.ls) <- names(pars.fit.2ps.10rbs)
mod.socs.2ps.20rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  soc.fx("2ps", pars.fit.2ps.20rbs[[i]], in.est[ix.20][[i]])
})
names(mod.socs.2ps.20rbs.ls) <- names(pars.fit.2ps.20rbs)
socs.2ps.10rbs.ls <- mapply(cbind,
                           csoc.19.0_30[ix.10], 
                           lapply(mod.socs.2ps.10rbs.ls, colSums), 
                           SIMPLIFY = FALSE)

## make df for plotting
# resp + bulk, w/ and w/o stocks
mod.socs.2ps.10brrbs.df <- rbind(mod.socs.df.fx("2ps w/o stock", mod.socs.2ps.10br.ls, c("fast", "slow"))
                                 ,mod.socs.df.fx("2ps w/ stock", mod.socs.2ps.10rbs.ls, c("fast", "slow"))
                                 ,data.frame(SOC = unlist(lapply(csoc.19.0_30[ix.10], "[[", 4)),
                                             PMeco_depth = paste0(
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 1)),
                                               "_",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 2)),
                                               "-",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 3))),
                                             Model = "measured",
                                             pool = "total")
                                 )
# bulk + stock, vs. resp, bulk, + stock
mod.socs.2ps.10bsrbs.df <- rbind(mod.socs.df.fx("2ps bulk + stock only", mod.socs.2ps.10bs.ls, c("fast", "slow"))
                                 ,mod.socs.df.fx("2ps bulk, resp, + stock", mod.socs.2ps.10rbs.ls, c("fast", "slow"))
                                 ,data.frame(SOC = unlist(lapply(csoc.19.0_30[ix.10], "[[", 4)),
                                             PMeco_depth = paste0(
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 1)),
                                               "_",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 2)),
                                               "-",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 3))),
                                             Model = "measured",
                                             pool = "total")
                                 )


## plot
mod.socs.2ps.10brrbs.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2ps.10bsrbs.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
#####

### Summarize optimized par data for plotting
## bulk 14c only
# 0-10
pars.fit.2ps.10b.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps.10b,
                                     pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30b.df <- par.fit.df.fx(mod = "2ps",
#                                       pars.fit = pars.fit.2ps.30b,
#                                       pars.i = pars.i.2ps[ix.30])

## resp + bulk 14c
# 0-10
pars.fit.2ps.10br.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10br,
                                       pars.i = pars.i.2ps[ix.10])
# 10-20
pars.fit.2ps.20br.l.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20br.l,
                                       pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

## bulk 14c + stocks
# 0-10
pars.fit.2ps.10bs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10bs,
                                       pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

## resp, bulk, stocks
# 0-10
pars.fit.2ps.10rbs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10rbs,
                                       pars.i = pars.i.2ps[ix.10])
# 10-20
pars.fit.2ps.20rbs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20rbs,
                                       pars.i = pars.i.2ps[ix.20])
# w/ lag
pars.fit.2ps.20rbs.l.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20rbs.l,
                                       pars.i = pars.i.2ps[ix.20])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

### Par fits
par.plot.fx(mod = "2ps bulk 14c",
            depth = "0-10",
            par.df = pars.fit.2ps.10b.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp + bulk 14c",
            depth = "0-10",
            par.df = pars.fit.2ps.10br.df,
            initial = FALSE)
par.plot.fx(mod = "2ps bulk 14c + stocks",
            depth = "0-10",
            par.df = pars.fit.2ps.10bs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "0-10",
            par.df = pars.fit.2ps.10rbs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "10-20",
            par.df = pars.fit.2ps.20rbs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "10-20",
            par.df = pars.fit.2ps.20rbs.l.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk",
            depth = "10-20",
            par.df = pars.fit.2ps.20br.l.df,
            initial = FALSE)
# par.plot.fx(mod = "2ps bulk 14c",
#             depth = "20-30",
#             par.df = pars.fit.2ps.30b.df,
#             initial = FALSE)
# par.plot.fx(mod = "2ps resp + bulk 14c",
#             depth = "20-30",
#             par.df = pars.fit.2ps.30br.df,
#             initial = FALSE)

### Fit models with optimized pars
## bulk 14C only
# 0-10
Twops.10b.fits <- lapply(seq_along(pars.fit.2ps.10b), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10b[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10b.fits) <- names(pars.fit.2ps.10b)
# # 20-30
# Twops.30b.fits <- lapply(seq_along(pars.fit.2ps.30b), function(i) {
#   tryCatch(
#     par.fx(pars.fit.2ps.30b[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
#     error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
# })
# names(Twops.30b.fits) <- names(pars.fit.2ps.30b)

## resp + bulk 14C
# 0-10
Twops.10br.fits <- lapply(seq_along(pars.fit.2ps.10br), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10br[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10br.fits) <- names(pars.fit.2ps.10br)
# 10-20
Twops.20br.l.fits <- lapply(seq_along(pars.fit.2ps.20br.l), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.20br.l[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.20br.l.fits) <- names(pars.fit.2ps.20br.l)
# # 20-30
# Twops.30br.fits <- lapply(seq_along(pars.fit.2ps.30br), function(i) {
#   tryCatch(
#     par.fx(pars.fit.2ps.30br[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
#     error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
# })
# names(Twops.30br.fits) <- names(pars.fit.2ps.30br)

## bulk 14C + stocks
# 0-10
Twops.10bs.fits <- lapply(seq_along(pars.fit.2ps.10bs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10bs[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10bs.fits) <- names(pars.fit.2ps.10bs)

## resp, bulk, stocks
# 0-10
Twops.10rbs.fits <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10rbs[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10rbs.fits) <- names(pars.fit.2ps.10rbs)
# 10-20
Twops.20rbs.fits <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.20rbs[[i]], in.est[ix.20][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.20rbs.fits) <- names(pars.fit.2ps.20rbs)

# # remove null entries
# Twops.10b.fits <- Filter(Negate(is.null), Twops.10b.fits)
# Twops.30b.fits <- Filter(Negate(is.null), Twops.30b.fits)
# Twops.10br.fits <- Filter(Negate(is.null), Twops.10br.fits)
# Twops.30br.fits <- Filter(Negate(is.null), Twops.30br.fits)

# Look at role of resp constraint in fit
# lapply(seq_along(Twops.10b.fits), function(i) {
#   C14.2p.plot.fx(Twops.10b.fits[[i]],
#                  con.df = con.df.fx(names(Twops.10b.fits)[i]), 
#                  mod = "2ps bulk only",
#                  PMeco_depth = names(Twops.10b.fits)[i])
# })
lapply(seq_along(Twops.10br.fits), function(i) {
  C14.2p.plot.fx(Twops.10br.fits[[i]], 
                 con.df = con.df.fx(names(Twops.10br.fits)[i]), 
                 mod = "2ps bulk + resp",
                 PMeco_depth = names(Twops.10br.fits)[i])
})
# lapply(seq_along(Twops.10bs.fits), function(i) {
#   C14.2p.plot.fx(Twops.10bs.fits[[i]],
#                  con.df = con.df.fx(names(Twops.10bs.fits)[i]), 
#                  mod = "2ps bulk + stock",
#                  PMeco_depth = names(Twops.10bs.fits)[i])
# })
lapply(seq_along(Twops.10rbs.fits), function(i) {
  C14.2p.plot.fx(Twops.10rbs.fits[[i]], 
                 con.df = con.df.fx(names(Twops.10rbs.fits)[i]), 
                 mod = "bulk, resp, stock",
                 PMeco_depth = names(Twops.10rbs.fits)[i])
})
# 10-20
lapply(seq_along(Twops.20rbs.fits), function(i) {
  C14.2p.plot.fx(Twops.20rbs.fits[[i]], 
                 con.df = con.df.fx(names(Twops.20rbs.fits)[i]), 
                 mod = "bulk, resp, stock",
                 PMeco_depth = names(Twops.20rbs.fits)[i])
})
# lapply(seq_along(Twops.30b.fits), function(i) {
#   C14.2p.plot.fx(Twops.30b.fits[[i]],
#                  con.df = con.df.fx(names(Twops.30b.fits)[i]), 
#                  mod = "2ps bulk only",
#                  PMeco_depth = names(Twops.30b.fits)[i])
# })
# lapply(seq_along(Twops.30br.fits), function(i) {
#   C14.2p.plot.fx(Twops.30br.fits[[i]], 
#                  con.df = con.df.fx(names(Twops.30br.fits)[i]), 
#                  mod = "2ps bulk + resp",
#                  PMeco_depth = names(Twops.30br.fits)[i])
# })

## Show role of resp in constraining models
# GRwf 0-10
Twop.fit.plot.fx(Twops.10bs.fits[which(names(Twops.10bs.fits) == "GRwf_0-10")], 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "GRwf_0-10")],
                 "2ps 0-10cm, resp & bulk 14c + stock")
# BSrf 0-10
Twop.fit.plot.fx(Twops.10br.fits[which(names(Twops.10br.fits) == "BSrf_0-10")], 
                 "2ps 0-10cm w/ resp", 
                 Twops.10b.fits[which(names(Twops.10b.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/o resp")
Twop.fit.plot.fx(Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/ resp, bulk, stocks",
                 Twops.10bs.fits[which(names(Twops.10bs.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/o resp (bulk + stocks only)")
Twop.fit.plot.fx(Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "BSwf_10-20")],
                 "Basalt/cool 10-20",
                 Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "GRwf_10-20")],
                 "Granite/cool 10-20")

# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.10rbs.fits, 
                 "2ps 0-10cm w/ resp, bulk, stocks", 
                 Twops.10br.fits,
                 "2ps 0-10cm w/ resp + bulk, no stock")
# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.10bs.fits, 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.10rbs.fits,
                 "2ps 0-10cm, resp & bulk 14c + stock")
# compare BSwf and GRwf 10-20
BSGRwf20.con.df <- cbind(rbind(con.df.fx("BSwf_10-20"), con.df.fx("GRwf_10-20")),
                               pm = factor(rep(c("basalt", "granite"), each = c(11))))
BSGRwf20.con.df <- BSGRwf20.con.df[-which(BSGRwf20.con.df$Year == 2009.5), ]
ANGRwf20.con.df <- cbind(rbind(con.df.fx("BSwf_10-20"), con.df.fx("GRwf_10-20")),
                               pm = factor(rep(c("basalt", "granite"), each = c(11))))
BSGRwf20.con.df <- BSGRwf20.con.df[-which(BSGRwf20.con.df$Year == 2009.5), ]
atm.14c2 <- Twops.20rbs.fits$`BSwf_10-20`[Twops.20rbs.fits$`BSwf_10-20`$years >= 1950 & Twops.20rbs.fits$`BSwf_10-20`$pool == "atm", ]
# plot
p <- rbind(Twops.20rbs.fits$`BSwf_10-20`,
      Twops.20rbs.fits$`GRwf_10-20`) %>%
  mutate(pm = rep(c("basalt", "granite"), 
                  each = nrow(Twops.20rbs.fits$`BSwf_10-20`))) %>%
  filter(pool == "bulk C" | pool == "respiration") %>%
  ggplot(., aes(years, d14C)) +
  geom_path(data = atm.14c2) +
  geom_path(aes(linetype = pool, color = pm)) +
  geom_point(data = BSGRwf20.con.df, 
             aes(Year, d14c, color = pm, shape = pool), 
             size = 2.5,
             position = position_dodge(width = 1)) +
  scale_color_manual(
    name = "Parent material",
    values = c("basalt" = "red",
               "granite" = "darkgray")) +
  scale_shape_manual(
    name = "",
    values = c("bulk C" = 16,
               "respiration" = 1)) +
  scale_linetype_manual(
   name = "Pool",
   values = c("bulk C" = 1,
              "respiration" = 2)) +
  scale_x_continuous(limits = c(1950, 2022)) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
ggsave("sra.2ps.BSGRwf20.pdf", p, dpi = 300, width = 6, height = 5, units = "in")
# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.20br.l.fits, 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.20rbs.fits,
                 "2ps 0-10cm, resp & bulk 14c + stock")
#####

# ages and transit times
#####
# 2ps
SA.2ps.20.rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  ks <- pars.fit.2ps.20rbs[[i]][1:2]
  tc <- pars.fit.2ps.20rbs[[i]][3]
  In <- in.est[ix.20][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(systemAge(A = A, u = c(In, 0)))
})
names(SA.2ps.20.rbs.ls) <- names(pars.fit.2ps.20rbs)
lapply(SA.2ps.20.rbs.ls, "[[", 1)

## Transit time
# 2ps
TT.2ps.20.rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  ks <- pars.fit.2ps.20rbs[[i]][1:2]
  tc <- pars.fit.2ps.20rbs[[i]][3]
  In <- in.est[ix.20][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(transitTime(A = A, u = c(In, 0)))
})
names(TT.2ps.20.rbs.ls) <- names(pars.fit.2ps.20rbs)
lapply(TT.2ps.20.rbs.ls, "[[", 1)
# 0-10
TT.MA.2ps.10.rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  ks <- pars.fit.2ps.10rbs[[i]][1:2]
  tc <- pars.fit.2ps.10rbs[[i]][3]
  In <- in.est[ix.10][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  TT <- transitTime(A = A, u = c(In, 0))
  Age <- systemAge(A = A, u = c(In, 0))
  return(list(TT = TT$meanTransitTime, Age = Age$meanSystemAge))
})
names(TT.MA.2ps.10.rbs.ls) <- names(pars.fit.2ps.10rbs)
lapply(TT.MA.2ps.10.rbs.ls, unlist)
# 
ageD.2ps.10.rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  ks <- pars.fit.2ps.10rbs[[i]][1:2]
  tc <- pars.fit.2ps.10rbs[[i]][3]
  In <- in.est[ix.10][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(systemAge(A = A, u = c(In, 0)))
})
names(ageD.2ps.10.rbs.ls) <- names(pars.fit.2ps.10rbs)
# compare output of 2pp and 2ps model fits
merge(ssr.2pp.df, ssr.2ps.df, by = "PMeco_depth", suffixes = c("_2pp", "_2ps")) %>%
  mutate(ssr_2pp = round(ssr_2pp, 1),
         ssr_2ps = round(ssr_2ps, 1),
         dif = ssr_2pp - ssr_2ps)
merge(var_ms.2pp.df,
      var_ms.2ps.df,
      by = c("PMeco_depth", "var"),
      suffixes = c("_2pp", "_2ps")) %>%
  mutate(var_ms_2pp = round(var_ms_2pp, 4),
         var_ms_2ps = round(var_ms_2ps, 4),
         dif = var_ms_2pp - var_ms_2ps)

## Plot
# SSR, PM
rbind(ssr.2pp.df, ssr.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(ssr.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(PM, mod) %>%
  summarize(mean.ssr = mean(ssr), sd = sd(ssr)) %>%
  mutate(err_u = mean.ssr + sd/sqrt(3),
         err_l = mean.ssr - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.ssr, fill = PM)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ PM) +
  ggtitle("SSR 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# SSR, eco
rbind(ssr.2pp.df, ssr.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(ssr.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(eco, mod) %>%
  summarize(mean.ssr = mean(ssr), sd = sd(ssr)) %>%
  mutate(err_u = mean.ssr + sd/sqrt(3),
         err_l = mean.ssr - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.ssr, fill = eco)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  facet_wrap(. ~ eco) +
  ggtitle("SSR 2-pool models 0-10 cm (eco)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# var_ms, PM
rbind(var_ms.2pp.df, var_ms.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(var_ms.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(var, PM, mod) %>%
  summarize(mean.var_ms = mean(var_ms), sd = sd(var_ms)) %>%
  mutate(err_u = mean.var_ms + sd/sqrt(3),
         err_l = mean.var_ms - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.var_ms, fill = PM)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ var, scales = "free") +
  ggtitle("Residual error 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# var_ms, eco
rbind(var_ms.2pp.df, var_ms.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(var_ms.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(var, eco, mod) %>%
  summarize(mean.var_ms = mean(var_ms), sd = sd(var_ms)) %>%
  mutate(err_u = mean.var_ms + sd/sqrt(3),
         err_l = mean.var_ms - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.var_ms, fill = eco)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  facet_wrap(. ~ var, scales = "free") +
  ggtitle("Residual error 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
## System age
# 2pp
SA.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  ks <- pars.fit.2pp[[i]][1:2]
  gam <- pars.fit.2pp[[i]][3]
  In <- in.fit.2pp[[i]]
  return(systemAge(, u = In))
})
names(SA.2pp.ls) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
SA.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  ks <- pars.fit.2pp.p3.5.95[[i]][1:2]
  gam <- pars.fit.2pp.p3.5.95[[i]][3]
  In <- in.fit.2pp.p3.5.95[[i]]
  return(systemAge(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(SA.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
# 2ps
SA.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  ks <- pars.fit.2ps[[i]][1:2]
  gam <- pars.fit.2ps[[i]][3]
  In <- in.fit.2ps[[i]]
  return(systemAge(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(SA.2ps.ls) <- names(pars.fit.2ps)

## Transit time
# 2pp
TT.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  ks <- pars.fit.2pp[[i]][1:2]
  gam <- pars.fit.2pp[[i]][3]
  In <- in.fit.2pp[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2pp.ls) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
TT.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  ks <- pars.fit.2pp.p3.5.95[[i]][1:2]
  gam <- pars.fit.2pp.p3.5.95[[i]][3]
  In <- in.fit.2pp.p3.5.95[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
# 2ps
TT.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  ks <- pars.fit.2ps[[i]][1:2]
  gam <- pars.fit.2ps[[i]][3]
  In <- in.fit.2ps[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2ps.ls) <- names(pars.fit.2ps)
# compare ages and transit times among the two model structures
SA.2p.ls <- list(SA.2pp.ls, SA.2ps.ls, SA.2pp.p3.5.95.ls)
SA.df <- bind_rows(
  lapply(SA.2p.ls, function(ls) {
    lapply(seq_along(ls), function(i) {
      data.frame(age = c(ls[[i]][["meanSystemAge"]],
                         ls[[i]][["meanPoolAge"]]),
                 component = c("system", "fast pool", "slow pool"))
    })
  })
)
SA.df$PMeco_depth <- rep(names(SA.2pp.ls), each = 3, times = length(SA.2p.ls))
SA.df$Model <- rep(c("2pp", "2ps", "2pp [.5, .95]"), each = 27)
TT.2p.ls <- list(TT.2pp.ls, TT.2ps.ls, TT.2pp.p3.5.95.ls)
TT.df <- bind_rows(
  lapply(TT.2p.ls, function(ls) {
    lapply(seq_along(ls), function(i) {
     data.frame(age = ls[[i]][["meanTransitTime"]],
                component = "transit")
    })
  })
)
TT.df$PMeco_depth <- rep(names(TT.2pp.ls), times = length(TT.2p.ls))
TT.df$Model <- rep(c("2pp", "2ps", "2pp [.5, .95]"), each = 9)
SA.TT.df <- rbind(SA.df, TT.df)
SA.TT.df$PM <- substr(SA.TT.df$PMeco_depth, start = 1, stop = 2)
SA.TT.df$eco <- substr(SA.TT.df$PMeco_depth, start = 3, stop = 4)

## Plot ages and transit times
# by PM
SA.TT.df %>%
  select(!c(PMeco_depth, eco)) %>%
  group_by(component, PM, Model) %>%
  summarize_all(list(mean_age = mean, sd = sd)) %>%
  mutate(err_u = mean_age + sd,
         err_l = mean_age - sd) %>%
  ggplot(., aes(Model, mean_age, fill = PM)) +
  geom_col(position = "dodge") +
  # geom_errorbar(
  #   aes(ymax = err_u, ymin = err_l), 
  #   position = position_dodge(width = .9),
  #   width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ component, scales = "free") +
  ylab("mean age") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# by eco
SA.TT.df %>%
  select(!c(PMeco_depth, PM)) %>%
  group_by(component, eco, Model) %>%
  summarize_all(list(mean_age = mean, sd = sd)) %>%
  mutate(err_u = mean_age + sd,
         err_l = mean_age - sd) %>%
  ggplot(., aes(Model, mean_age, fill = eco)) +
  geom_col(position = "dodge") +
  # geom_errorbar(
  #   aes(ymax = err_u, ymin = err_l),
  #   position = position_dodge(width = .9),
  #   width = .3) +
  facet_wrap(. ~ component, scales = "free") +
  ylab("mean age") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Bayesian parameter estimation (MCMC)

# the following .RData files are generated by script "sra-ts/source/sra-ts-mcmc-bayes.R"
load(file = "../data/derived/bayes-par-fit-2020-11-06/bayes_fit_2pp_0-10_5000iter.RData")
load(file = "../data/derived/bayes-par-fit-2020-11-17/bayes_fit_2ps_0-10_5000iter.RData")

# # plot parameter convergence
# lapply(bayes_fit_2pp_0_10, plot)
# lapply(bayes_fit_2ps_0_10, plot)

# plot collinearity
iter <- 5000
lapply(bayes_fit_2pp_0_10, pairs, nsample = floor(iter/4))
lapply(bayes_fit_2ps_0_10, pairs, nsample = floor(iter/4))

## look at model performance
pars.bayes.df.fx <- function(mod, pars.bayes, pars.fit) {
  bind_rows(lapply(seq_along(pars.bayes), function(i) {
    ix <- match(unique(pars.bayes[[i]][["pars"]][, 1]), pars.bayes[[i]][["pars"]][, 1])
    df <- data.frame(k1 = pars.bayes[[i]][["pars"]][ix, 1],
                     k2 = pars.bayes[[i]][["pars"]][ix, 2],
                     p3 = pars.bayes[[i]][["pars"]][ix, 3])
    df <- cbind(df,
                PMeco_depth = rep(names(pars.fit)[i], length(ix)),
                mod = rep(mod, length(ix)))
    df <- cbind(df, 
                PM = factor(substr(df$PMeco_depth, 1, 2)),
                eco = factor(substr(df$PMeco_depth, 3, 4), levels = c("pp", "wf", "rf")))
    return(df)
  }))
}
pars.bayes.2pp.df <- pars.bayes.df.fx("2pp", bayes_fit_2pp_0_10, pars.fit.2pp)
pars.bayes.2ps.df <- pars.bayes.df.fx("2ps", bayes_fit_2ps_0_10, pars.fit.2ps)

# # linear fits
# summary(lm(k2 ~ PM, pars.bayes.2pp.df))
# summary(lm(k2 ~ eco, pars.bayes.2pp.df))
# summary(lm(k1 ~ PM, pars.bayes.2pp.df))
# summary(lm(k1 ~ eco, pars.bayes.2pp.df))
# summary(lm(p3 ~ PM, pars.bayes.2pp.df))
# summary(lm(p3 ~ eco, pars.bayes.2pp.df))

# best par set
bestPars.bayes.ls <- lapply(bayes_fit_2pp_0_10, function(x) {
  round(data.frame(k1 = x$bestpar[1],
                   k2 = x$bestpar[2],
                   gam = x$bestpar[3]),
        4)
})
bestPars.bayes.df <- cbind(PM = rep(c("AN", "BS", "GR"), each = 3),
                           eco = rep(c("pp", "rf", "wf"), 3),
                           depth = rep("0-10", 9),
                           bind_rows(bestPars.bayes.ls))

# summarize by PM
pars.bayes.PM <- bestPars.bayes.df %>%
  select(!c(eco, depth)) %>%
  group_by(PM) %>%
  summarize_all(list(mean = mean, sd = sd)) %>%
  mutate_if(is.numeric, format, digits = 3)
# summarize by ECO
pars.bayes.eco <- bestPars.bayes.df %>%
  select(!c(PM, depth)) %>%
  group_by(eco) %>%
  summarize_all(list(mean = mean, sd = sd)) %>%
  mutate_if(is.numeric, format, digits = 3)

# plot best pars
bestPars.bayes.df %>%
  pivot_longer(!(PM:depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, color = PM, shape = eco)) +
  geom_jitter(size = 4) +
  scale_color_manual(name = "parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# plot accepted pars by PM and then by eco
pars.bayes.df %>%
  pivot_longer(!c(PM, eco, PMeco_depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, fill = PM)) +
  geom_boxplot() +
  scale_fill_manual(name = "parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
pars.bayes.df %>%
  pivot_longer(!c(PM, eco, PMeco_depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, fill = eco)) +
  geom_boxplot() +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
LS0tCnRpdGxlOiAiU2llcnJhIE5ldmFkYSBUaW1lIFNlcmllcyIKYXV0aG9yOiAiSi4gQmVlbS1NaWxsZXIiCmRhdGU6ICIyMSBPY3QgMjAyMCIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDoKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICBjc3M6IGN1c3RvbS5jc3MKaGVhZGVyX2luY2x1ZGVzOgogIC0gXHVzZXBhY2thZ2VbdXRmOF17aW5wdXRlbmN9CiAgLSBcdXNlcGFja2FnZXtmbG9hdH0KLS0tCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gJ2NlbnRlcicsIGRldiA9ICdjYWlyb19wZGYnKQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKIyBzdXBwcmVzcyBncm91cGluZyBpbmZvcm1hdGlvbiBtZXNzYWdlCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQpsaWJyYXJ5KElTUmFEKQpsaWJyYXJ5KEdTSUYpCmxpYnJhcnkoYXFwKQpsaWJyYXJ5KFNvaWxSKQpsaWJyYXJ5KEZNRSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ3QpCmBgYAoKIyBEYXRhIHByZXBhcmF0aW9uIHNjcmlwdCBmb3IgU2llcnJhIE5ldmFkYSB0aW1lIHNlcmllcyBhbmFseXNpcwoKYGBge3IgbG9hZCBhbXMtamVuYS1pbmdlc3QgZnh9CiMgMS4gUmVhZCBpbiBpc290b3BlIGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMKIyBGaXJzdCBsb2FkIGhlbHBlciBmdW5jdGlvbnMgJ3JlYWRfamVuYV9hbXNfcmVzdWx0cy5SJywgJ3JlYWRfamVuYV9pc29fcmVzdWx0cy5SJyAKc291cmNlKCIuL3V0aWxpdGllcy9qZW5hX2Ftc19pbmdlc3QuUiIpCnNvdXJjZSgiLi91dGlsaXRpZXMvamVuYV9pc29faW5nZXN0LlIiKQpzb3VyY2UoIi4vdXRpbGl0aWVzL2plbmFfZWxtX2luZ2VzdC5SIikKYGBgCgpgYGB7ciByZWFkLWNuLWlzby1kYXRhLCBpbmNsdWRlID0gRkFMU0V9CiMgMi4gTmV4dCByZWFkIGluIGRhdGEgZnJvbSB0aGUgYXBwcm9wcmlhdGUgZGlyZWN0b3JpZXMgaW4gJ2RhdGEvcmF3JwojIDE0QwojIGlkZW50aWZ5IHN1YmRpcmVjdG9yaWVzIGluICdyYXcnIGRpcmVjdG9yeSB3aXRoICJhbXNfamVuYSIgaW4gbmFtZQphbXNfamVuYV9yZXN1bHRzX2RpcnMgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9yYXciLCBwYXR0ZXJuID0gImFtc19qZW5hX3Jlc3VsdHMiLCBmdWxsLm5hbWVzID0gVFJVRSkKYW1zX3Jlc3VsdHNfbHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhhbXNfamVuYV9yZXN1bHRzX2RpcnMpLCBmdW5jdGlvbihpKSB7CiAgcmVhZF9qZW5hX2Ftc19yZXN1bHRzKGFtc19qZW5hX3Jlc3VsdHNfZGlyc1tpXSkKfSkKbmFtZXMoYW1zX3Jlc3VsdHNfbHMpIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvcmF3IiwgcGF0dGVybiA9ICJhbXNfamVuYV9yZXN1bHRzIikKCiMgIyAxM0MKIyAjIGlkZW50aWZ5IHN1YmRpcmVjdG9yaWVzIGluICdyYXcnIGRpcmVjdG9yeSB3aXRoICJpc29famVuYSIgaW4gbmFtZQojIGlzb19qZW5hX3Jlc3VsdHNfZGlycyA8LSBsaXN0LmZpbGVzKCIuLi9kYXRhL3JhdyIsIHBhdHRlcm4gPSAiaXNvX2plbmFfcmVzdWx0cyIsIGZ1bGwubmFtZXMgPSBUUlVFKQojIGlzb19yZXN1bHRzX2xzIDwtIGxhcHBseShzZXFfYWxvbmcoaXNvX2plbmFfcmVzdWx0c19kaXJzKSwgZnVuY3Rpb24oaSkgewojICAgcmVhZF9qZW5hX2lzb19yZXN1bHRzKGlzb19qZW5hX3Jlc3VsdHNfZGlyc1tpXSkKIyB9KQojIG5hbWVzKGlzb19yZXN1bHRzX2xzKSA8LSBsaXN0LmZpbGVzKCIuLi9kYXRhL3JhdyIsIHBhdHRlcm4gPSAiaXNvX2plbmFfcmVzdWx0cyIpCgojIFJlYWQgaW4gQyBhbmQgTiBkYXRhCmVsbV9yZXN1bHRzX2RpciA8LSBsaXN0LmZpbGVzKCIuLi9kYXRhL3JhdyIsIHBhdHRlcm4gPSAiZWxtX2plbmFfcmVzdWx0cyIsIGZ1bGwubmFtZXMgPSBUUlVFKQplbG1fcmVzdWx0c19scyA8LSBsYXBwbHkoc2VxX2Fsb25nKGVsbV9yZXN1bHRzX2RpciksIGZ1bmN0aW9uKGkpIHsKICByZWFkX2plbmFfZWxtX3Jlc3VsdHMoZWxtX3Jlc3VsdHNfZGlyW2ldKQp9KQpuYW1lcyhlbG1fcmVzdWx0c19scykgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9yYXciLCBwYXR0ZXJuID0gImVsbV9qZW5hX3Jlc3VsdHMiKQpgYGAKCmBgYHtyIGRhdGEtdGVtcGxhdGV9CiMgQ3JlYXRlIHRlbXBsYXRlIGZvciBidWxrIHNvaWwgZGF0YQp0ZW1wbGF0ZTE5LmZ4IDwtIGZ1bmN0aW9uKHBtLCBlY28sIG5kZXB0aCkgewogIGRmIDwtIGRhdGEuZnJhbWUoWWVhciA9IHJlcCgyMDE5LCBuZGVwdGggKiAzKSwKICAgICAgICAgICAgICAgICAgIFBNID0gcmVwKHBtLCBuZGVwdGggKiAzKSwKICAgICAgICAgICAgICAgICAgIEVDTyA9IHJlcChlY28sIG5kZXB0aCAqIDMpLAogICAgICAgICAgICAgICAgICAgcHJvX3JlcCA9IHJlcChzZXEoMSwzKSwgZWFjaCA9IG5kZXB0aCksCiAgICAgICAgICAgICAgICAgICBseXJfdG9wID0gcmVwKHNlcSgwLCAobmRlcHRoLTEpICogMTAsIGJ5ID0gMTApLCAzKSwKICAgICAgICAgICAgICAgICAgIGx5cl9ib3QgPSByZXAoc2VxKDEwLCAobmRlcHRoKSAqIDEwLCBieSA9IDEwKSwgMykpCiAgZGYkcHJvX25hbWUgPC0gcGFzdGUwKGRmJFBNLCBkZiRFQ08sICJfIiwgZGYkcHJvX3JlcCkKICBkZiRseXJfbmFtZSA8LSBwYXN0ZTAoZGYkcHJvX25hbWUsICJfIiwgZGYkbHlyX3RvcCwgIi0iLCBkZiRseXJfYm90KQogIHJldHVybihkZikKfQoKIyBDcmVhdGUgdGVtcGxhdGUgZm9yIGNvbXBvc2l0ZSBzb2lsIGRhdGEgKGluY3ViYXRpb25zLCBkZW5zaXR5IGZyYWN0aW9ucywgZXRjLikKdGVtcGxhdGUuY29tcC5meCA8LSBmdW5jdGlvbih5ZWFyLCBwbSwgZWNvLCBkZXB0aF9ib3QgPSBjKDEwLCAyMCwgMzApLCBkYXQpIHsKICBuZGVwdGggPC0gbGVuZ3RoKGRlcHRoX2JvdCkKICBkZiA8LSBkYXRhLmZyYW1lKFllYXIgPSByZXAoeWVhciwgbmRlcHRoICogbGVuZ3RoKHBtKSksCiAgICAgICAgICAgICAgICAgICBQTSA9IHJlcChwbSwgZWFjaCA9IG5kZXB0aCAqIGxlbmd0aChlY28pKSwKICAgICAgICAgICAgICAgICAgIEVDTyA9IHJlcChlY28sIGVhY2ggPSBuZGVwdGgpKQogIGRmJGx5cl9ib3QgPC0gZGVwdGhfYm90CiAgZGYkbHlyX3RvcCA8LSBzYXBwbHkoc2VxX2Fsb25nKGRlcHRoX2JvdCksIGZ1bmN0aW9uKGkpIHsKICAgIGlmIChpID09IDEpIHsKICAgICAgZGVwdGhfdG9wIDwtIDAKICAgICAgfSBlbHNlIHsKICAgICAgICBkZXB0aF90b3AgPC0gZGVwdGhfYm90W2kgLSAxXQogICAgICB9CiAgfSkKICBkZiRwcm9fbmFtZSA8LSBwYXN0ZTAoZGYkUE0sIGRmJEVDTywgIl9jb21wIikKICBuIDwtIG5yb3coZGYpCiAgaWYgKGRhdCA9PSAiaW5jIikgewogICAgZGYgPC0gcmJpbmQoZGYsIGRmKQogICAgZGYkcmVwIDwtIHJlcChjKCJhIiwgImIiKSwgZWFjaCA9IG4pCiAgICBkZiRseXJfbmFtZSA8LSBwYXN0ZTAoZGYkcHJvX25hbWUsICJfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGYkbHlyX3RvcCwgIi0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRseXJfYm90LCAiXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmJFllYXIsICJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRyZXApCiAgfSBlbHNlIGlmIChkYXQgPT0gImRlbnNpdHkiKSB7CiAgICBkZiA8LSByYmluZChkZiwgZGYsIGRmKQogICAgZGYkZnJjIDwtIHJlcChjKCJmTEYiLCAib0xGIiwgIm1uQyIpLCBlYWNoID0gbikKICAgIGRmJGx5cl9uYW1lIDwtIHBhc3RlMChkZiRwcm9fbmFtZSwgIl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRseXJfdG9wLCAiLSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmJGx5cl9ib3QsICJfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGYkWWVhciwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmJGZyYykKICB9CiAgcmV0dXJuKGRmKQp9CgojIHRlbXBsYXRlcyBmb3IgYnVsayBzb2lsIGRhdGEKIyBHUnJmIApHUnJmIDwtIHRlbXBsYXRlMTkuZngoIkdSIiwgInJmIiwgNykKR1JyZiA8LSBpZihhbnkoR1JyZiRseXJfbmFtZSA9PSAiR1JyZl8xXzYwXzcwIikpIHsKICBHUnJmIDwtIEdScmZbLXdoaWNoKEdScmYkbHlyX25hbWUgPT0gIkdScmZfMV82MF83MCIpLCBdICMgTkI6IEdScmZfMV82MF83MCBkb2Vzbid0IGV4aXN0Cn0gZWxzZSB7CiAgR1JyZiA8LSBHUnJmCn0KIyBHUndmCkdSd2YgPC0gdGVtcGxhdGUxOS5meCgiR1IiLCAid2YiLCA5KQojIEdScHAKR1JwcCA8LSB0ZW1wbGF0ZTE5LmZ4KCJHUiIsICJwcCIsIDgpCgojIEFOcmYgCkFOcmYgPC0gdGVtcGxhdGUxOS5meCgiQU4iLCAicmYiLCA2KQojIEFOd2YKQU53ZiA8LSB0ZW1wbGF0ZTE5LmZ4KCJBTiIsICJ3ZiIsIDYpCiMgQU5wcApBTnBwIDwtIHRlbXBsYXRlMTkuZngoIkFOIiwgInBwIiwgOCkKCiMgQlNyZiAKQlNyZiA8LSB0ZW1wbGF0ZTE5LmZ4KCJCUyIsICJyZiIsIDgpCkJTcmYgPC0gaWYoYW55KEJTcmYkbHlyX25hbWUgPT0gIkdScmZfMV82MF83MCIpKSB7CiAgQlNyZiA8LSBCU3JmWy13aGljaChCU3JmJGx5cl9uYW1lID09ICJCU3JmXzFfNzBfODAiKSwgXSAjIE5COiBCU3JmXzFfNzBfODAgZG9lc24ndCBleGlzdAp9IGVsc2UgewogIEJTcmYgPC0gQlNyZgp9IAojIEJTd2YKQlN3ZiA8LSB0ZW1wbGF0ZTE5LmZ4KCJCUyIsICJ3ZiIsIDcpCiMgQlNwcApCU3BwIDwtIHRlbXBsYXRlMTkuZngoIkJTIiwgInBwIiwgOCkKQlNwcFtCU3BwJGx5cl9ib3QgPT0gODAsICJseXJfYm90Il0gPC0gNzUgIyBvbmx5IHNhbXBsZWQgdG8gNzVjbSwgbm90IDgwCgpzcmEuMjAxOS5kZiA8LSByYmluZChHUnJmLCBHUndmLCBHUnBwLAogICAgICAgICAgICAgICAgICAgICBBTnJmLCBBTndmLCBBTnBwLAogICAgICAgICAgICAgICAgICAgICBCU3JmLCBCU3dmLCBCU3BwKQoKIyB0ZW1wbGF0ZSBmb3IgMjAxOSBpbmN1YmF0aW9uIGRhdGEKc3JhLjIwMTkuaW5jLmRmIDwtIHRlbXBsYXRlLmNvbXAuZngoMjAxOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtID0gYygiQU4iLCAiQlMiLCAiR1IiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNvID0gYygicHAiLCAid2YiLCAicmYiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ID0gImluYyIpCgojIyB0ZW1wbGF0ZSBmb3IgMjAwMSBpbmN1YmF0aW9uIGRhdGEKIyBsaXN0IG9mIGRlcHRocyBmb3IgMjAwMSBpbmMgc2FtcGxlcwpkZXB0aF9ib3RfMjAwMS5scyA8LSBsaXN0KEFOcHAgPSBjKDYsIDEzLCAzMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgQU53ZiA9IGMoMTEsIDM1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBBTnJmID0gYygxMSwgMzIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEJTcHAgPSBjKDcsIDE4LCAyOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgQlN3ZiA9IGMoMTAsIDE5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBCU3JmID0gYyg4LCAxNSwgMzApLAogICAgICAgICAgICAgICAgICAgICAgICAgIEdScHAgPSBjKDcsIDE1LCAyNyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgR1J3ZiA9IGMoNCwgMTMsIDI4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBHUnJmID0gYyg4LCAyNykpIAojIHRlbXBsYXRlIGZvciBpbnB1dHMgdG8gdGVtcGxhdGUuY29tcC5meCAoeWVhciwgcG0sIGVjbykKaW5jLjIwMDEudGVtcGxhdGUgPC0gbGFwcGx5KHNlcV9hbG9uZyhkZXB0aF9ib3RfMjAwMS5scyksIGZ1bmN0aW9uKGkpIHsKICBubXMgPC0gbmFtZXMoZGVwdGhfYm90XzIwMDEubHMpCiAgbHMgPC0gbGlzdCh5ZWFyID0gMjAwMSwgCiAgICAgICAgICAgICBwbSA9IHN1YnN0cihubXNbaV0sIDEsIDIpLCAKICAgICAgICAgICAgIGVjbyA9IHN1YnN0cihubXNbaV0sIDMsIDQpKQogIGxzJGRlcHRoX2JvdCA8LSBkZXB0aF9ib3RfMjAwMS5sc1tbaV1dCiAgcmV0dXJuKGxzKQp9KQojIGNyZWF0ZSB0ZW1wbGF0ZSBkYXRhIGZyYW1lIGJ5IGl0ZXJhdGl2ZWx5IGNhbGxpbmcgdGVtcGxhdGUuY29tcC5meApzcmEuMjAwMS5pbmMuZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShzZXFfYWxvbmcoaW5jLjIwMDEudGVtcGxhdGUpLCBmdW5jdGlvbihpKSB7CiAgICB0ZW1wbGF0ZS5jb21wLmZ4KHllYXIgPSBpbmMuMjAwMS50ZW1wbGF0ZVtbaV1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgIHBtID0gaW5jLjIwMDEudGVtcGxhdGVbW2ldXVtbMl1dLAogICAgICAgICAgICAgICAgICAgICBlY28gPSBpbmMuMjAwMS50ZW1wbGF0ZVtbaV1dW1szXV0sCiAgICAgICAgICAgICAgICAgICAgIGRlcHRoX2JvdCA9IGluYy4yMDAxLnRlbXBsYXRlW1tpXV1bWzRdXSwKICAgICAgICAgICAgICAgICAgICAgZGF0ID0gImluYyIpCiAgfSkKKQoKIyAyMDAxIGJ1bGsgc29pbCB0ZW1wbGF0ZQpzcmEuMjAwMSA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKHVuaXF1ZShzcmEuMjAxOS5kZiRwcm9fbmFtZSkpKQpuYW1lcyhzcmEuMjAwMSkgPC0gdW5pcXVlKHNyYS4yMDE5LmRmJHByb19uYW1lKQoKIyAyMDE5IGJ1bGsgc29pbCB0ZW1wbGF0ZQpzcmEuMjAxOSA8LSBzcmEuMjAwMQoKIyBpbmMgdGVtcGxhdGVzIGZvciBtZXJnaW5nIDE0QyBkYXRhCnNyYS4yMDE5LmluYyA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKHVuaXF1ZShzcmEuMjAxOS5pbmMuZGYkcHJvX25hbWUpKSkKbmFtZXMoc3JhLjIwMTkuaW5jKSA8LSB1bmlxdWUoc3JhLjIwMTkuaW5jLmRmJHByb19uYW1lKQpzcmEuMjAwMS5pbmMgPC0gc3JhLjIwMTkuaW5jCiMgY29waWVzIGZvciByZXBzIG9mIGluY3ViYXRpb25zCnNyYS4yMDE5LmluY19MIDwtIHNyYS4yMDE5LmluYwpuYW1lcyhzcmEuMjAxOS5pbmNfTCkgPC0gc3Vic3RyKG5hbWVzKHNyYS4yMDE5LmluY19MKSwgMSwgNCkKYGBgCgpgYGB7ciBhdmVyYWdlLWNuLWRhdGF9CiMgY29tcGxldGUgY2FzZXMsIGNvbnZlcnQgdHlwZSBmb3IgY2FsY3VsYXRpbmcgc3RvY2tzIGxhdGVyCiMgY291bGQgY2FsY3VsYXRlIHN0b2NrcyBub3cgYW5kIHRoZW4gcmVtb3ZlIGZvciB0aGUgZm9sbG93aW5nIHN0ZXBzIHdoZXJlIG5vdCBuZWVkZWQKCiMjIDIwMDEgc3VtbWFyeSBkYXRhCnNvYy4yMDAxIDwtIGRhdGEuZnJhbWUocmVhZF9leGNlbCgiLi4vZGF0YS9leHRlcm5hbC9zcmFfcmFzX3N1bS9zaWVycmFfZGF0YV9zdW1tYXJ5XzIwMjAueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICIyMDAxX2J1bGtfZGF0YSIpKQoKIyBjcmVhdGUgbGlzdDsgcmVtb3ZlIEJTIHNhbXBsZXMgZGVlcGVyIHRoYW4gMzAgY20Kc29jLjIwMDEubHMgPC0gbGFwcGx5KHNwbGl0KHNvYy4yMDAxLCBzb2MuMjAwMSRQTWVjbyksIGZ1bmN0aW9uKGRmKSB7CiAgZGYgPC0gdHlwZS5jb252ZXJ0KGRmW2NvbXBsZXRlLmNhc2VzKGRmKSwgYygiSUQiLCAiQy4iLCAiYmQuZy5jbTMiLCAiUE1lY28iLCAicHJvX3JlcCIsICJseXJfdG9wIiwgImx5cl9ib3QiKV0pCiByZXR1cm4oZGZbd2hpY2goZGYkbHlyX2JvdCA8IDM2KSwgXSkKfSkKCiMgSW5jdWJhdGlvbiBzYW1wbGVzIGNvbWJpbmVkIDAtMyBhbmQgMy04IGRlcHRoIGluY3JlbWVudHMgZm9yIEJTcmYgYW5kIEdScmYKIyBjb21iaW5lIEJTcmYgYW5kIEdScmYgaW5pdGlhbCBkZXB0aHMKIyBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgd2VpZ2h0ZWQgYXZlcmFnZSBvZiBmaXJzdCB0d28gZGVwdGggaW5jcmVtZW50IEMgY29udGVudApkMWQyLmZ4IDwtIGZ1bmN0aW9uKGRmKSB7CiAgZDFkMiA8LSBkYXRhLmZyYW1lKElEID0gcGFzdGUoZGYkUE1lY29bMV0sIGRmJHByb19yZXBbMV0sIGRmJGx5cl90b3BbMV0sIGRmJGx5cl9ib3RbMl0sIHNlcCA9ICJfIiksCiAgICAgICAgICAgICAgICAgICAgIEMuID0gc3VtKGRmJEMuWzFdICogKChkZiRseXJfYm90WzFdIC0gZGYkbHlyX3RvcFsxXSkgLyBkZiRseXJfYm90WzJdKSwgZGYkQy5bMl0gKiAoKGRmJGx5cl9ib3RbMl0gLSBkZiRseXJfdG9wWzJdKSAvIGRmJGx5cl9ib3RbMl0pKSwKICAgICAgICAgICAgICAgICAgICAgYmQuZy5jbTMgPSBkZiRiZC5nLmNtM1sxXSwKICAgICAgICAgICAgICAgICAgICAgUE1lY28gPSBkZiRQTWVjb1sxXSwKICAgICAgICAgICAgICAgICAgICAgcHJvX3JlcCA9IGRmJHByb19yZXBbMV0sCiAgICAgICAgICAgICAgICAgICAgIGx5cl90b3AgPSBkZiRseXJfdG9wWzFdLAogICAgICAgICAgICAgICAgICAgICBseXJfYm90ID0gZGYkbHlyX2JvdFsyXSkKICByZXR1cm4ocmJpbmQoZDFkMiwKICAgICAgICAgICAgICAgZGZbMzpucm93KGRmKSwgXSkpCn0KIyBSdW4gZDFkMi5meCBmb3IgQlNyZiwgR1JyZgpzb2MuMjAwMS5scy5pbmMgPC0gc29jLjIwMDEubHMgCnNvYy4yMDAxLmxzLmluYyRHUnJmIDwtIGJpbmRfcm93cyhsYXBwbHkoc3BsaXQoc29jLjIwMDEubHMkR1JyZiwgc29jLjIwMDEubHMkR1JyZiRwcm9fcmVwKSwgZDFkMi5meCkpCnNvYy4yMDAxLmxzLmluYyRCU3JmIDwtIGJpbmRfcm93cyhsYXBwbHkoc3BsaXQoc29jLjIwMDEubHMkQlNyZiwgc29jLjIwMDEubHMkQlNyZiRwcm9fcmVwKSwgZDFkMi5meCkpCgojIGNhbGN1bGF0ZSBTT0Mgc3RvY2tzCnNvYy4yMDAxLmxzIDwtIGxhcHBseShzb2MuMjAwMS5scywgZnVuY3Rpb24oZGYpIHsKICBkZiRseXJfc29jX2tnbTIgPC0gZGYkQy4gKiBkZiRiZC5nLmNtMyAqIChkZiRseXJfYm90IC0gZGYkbHlyX3RvcCkgKiAxMF4tMQogIHJldHVybihkZikKfSkKCiMgc3VtbWFyaXplIFtub3RlIHRoYXQgc29jIHN0b2NrcyBhcmUgZHJvcHBlZF0Kc29jLjIwMDEuc3VtIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShzb2MuMjAwMS5scywgZnVuY3Rpb24oZGYpIHsKICBkZiAlPiUKICAgIG11dGF0ZShJRDIgPSBwYXN0ZTAoUE1lY28sICJfIiwgbHlyX3RvcCwgIi0iLCBseXJfYm90KSkgJT4lCiAgICBncm91cF9ieShJRDIsIGJkLmcuY20zLCBQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkgJT4lCiAgICBzdW1tYXJpemUoY19wY3RfYXZnID0gbWVhbihDLikpCn0pKSkKCiMgMjAxOSBkYXRhCnNyYS4yMDE5LmNuLnN1bSA8LSBkYXRhLmZyYW1lKAogIGJpbmRfcm93cyh1bmxpc3QoZWxtX3Jlc3VsdHNfbHMsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkgJT4lCiAgbXV0YXRlKFBNZWNvID0gc2FwcGx5KHN0cnNwbGl0KElELCAiXyIpLCAiWyIsIDIpLAogICAgICAgICBkZXB0aCA9IHNhcHBseShzdHJzcGxpdChJRCwgIl8iKSwgIlsiLCA0KSkgJT4lCiAgZ3JvdXBfYnkoUE1lY28sIGRlcHRoKSAlPiUKICBzdW1tYXJpemUoY19wY3RfYXZnID0gbWVhbihDKSkpCnNyYS4yMDE5LmNuLnN1bSRJRDIgPC0gcGFzdGUoc3JhLjIwMTkuY24uc3VtJFBNZWNvLCBzcmEuMjAxOS5jbi5zdW0kZGVwdGgsIHNlcCA9ICJfIikKYGBgCgpgYGB7ciByZWFkLXJlc3AtdHN9CiMjIHJlYWQgaW4gdGltZXNlcmllcyBvZiBDTzIgcmVsZWFzZSBmcm9tIGluY3ViYXRpb25zCiMgMjAxOQpzcmEuMTlhLmNvMi50cyA8LSByZWFkLmNzdigiLi4vZGF0YS9kZXJpdmVkL2xhYl9qZW5hX0NPMi10aW1lc2VyaWVzL1MxOWFfQ08yX2ZsdXhfMjAyMS0wMS0xOS5jc3YiKQpzcmEuMTliLmNvMi50cyA8LSByZWFkLmNzdigiLi4vZGF0YS9kZXJpdmVkL2xhYl9qZW5hX0NPMi10aW1lc2VyaWVzL1MxOWJfQ08yX2ZsdXhfMjAyMS0wMS0xOS5jc3YiKQoKIyAyMDAxCnNyYS4wMS4xLmNvMi50cyA8LSByZWFkLmNzdigiLi4vZGF0YS9kZXJpdmVkL2xhYl9qZW5hX0NPMi10aW1lc2VyaWVzL1MwMV8xX0NPMl9mbHV4XzIwMjEtMDEtMjcuY3N2IikKc3JhLjAxLjIuY28yLnRzIDwtIHJlYWQuY3N2KCIuLi9kYXRhL2Rlcml2ZWQvbGFiX2plbmFfQ08yLXRpbWVzZXJpZXMvUzAxXzJfQ08yX2ZsdXhfMjAyMS0wMS0yNy5jc3YiKQoKIyMgVGVzdCB0aGF0IHJlcXVpcmVkIG5hbWVzIGFyZSBwcmVzZW50Cm5tcyA8LSBjKCJQTWVjbyIsICJJRCIsICJkd19nIiwgInRpbWVwb2ludF9jbXR2IiwgICJ0aW1lX2QiLCAibWdDTzJfamFyIikKaW52aXNpYmxlKGxhcHBseShsaXN0KHNyYS4xOWEuY28yLnRzLAogICAgICAgICAgICAgICAgICAgICAgc3JhLjE5Yi5jbzIudHMsCiAgICAgICAgICAgICAgICAgICAgICBzcmEuMDEuMS5jbzIudHMsCiAgICAgICAgICAgICAgICAgICAgICBzcmEuMDEuMi5jbzIudHMpLAogICAgICAgZnVuY3Rpb24oeCkgewogICAgICAgICBpZmVsc2UoIWlzLm5hKG1hdGNoKG5tcywgbmFtZXMoeCkpKSwgInllcyIsICJubyIpCiAgICAgICB9CiAgICAgICApKQoKIyBjb21iaW5lIGFsbCBkYXRhLCByZW1vdmUgdGltZSBwb2ludHMgd2l0aG91dCBDTzIgbWVhc3VyZW1lbnRzLCBhbmQgYWRkIHllYXIgYW5kIHJlcCAKdHMgPC0gYmluZF9yb3dzKHNyYS4xOWEuY28yLnRzWyAsIG5tc10sIAogICAgICAgICAgICAgICAgc3JhLjE5Yi5jbzIudHNbICwgbm1zXSwgCiAgICAgICAgICAgICAgICBzcmEuMDEuMS5jbzIudHNbICwgbm1zXSwKICAgICAgICAgICAgICAgIHNyYS4wMS4yLmNvMi50c1sgLCBubXNdKQppZihsZW5ndGgod2hpY2goaXMubmEodHMkbWdDTzJfamFyKSkpID4gMCkgewogIHRzIDwtIHRzWy13aGljaChpcy5uYSh0cyRtZ0NPMl9qYXIpKSwgXQp9CnRzJHllYXIgPC0gc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3Rlcih0cyRJRCksICJfIiksICJbWyIsIDMpCnRzJHJlcCA8LSBzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHRzJElEKSwgIl8iKSwgIltbIiwgNCkKdHMkZGVwdGggPC0gc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3Rlcih0cyRJRCksICJfIiksICJbWyIsIDIpCnRzJElEMiA8LSBwYXN0ZSh0cyRQTWVjbywgdHMkZGVwdGgsIHNlcCA9ICJfIikKCiMgYWRkIEMgY29udGVudAp0c1t3aGljaCh0cyR5ZWFyID09IDIwMDEpLCAiZ0NfZ1MiXSA8LSBzb2MuMjAwMS5zdW1bbWF0Y2godHNbd2hpY2godHMkeWVhciA9PSAyMDAxKSwgIklEMiJdLCBzb2MuMjAwMS5zdW0kSUQyKSwgImNfcGN0X2F2ZyJdICogMTBeLTIKdHNbd2hpY2godHMkeWVhciA9PSAyMDE5KSwgImdDX2dTIl0gPC0gc3JhLjIwMTkuY24uc3VtW21hdGNoKHRzW3doaWNoKHRzJHllYXIgPT0gMjAxOSksICJJRDIiXSwgc3JhLjIwMTkuY24uc3VtJElEMiksICJjX3BjdF9hdmciXSAqIDEwXi0yCgojIGNhbGN1bGF0ZSBwZXIgdW5pdCBjYXJib24gZmx1eGVzCnRzJG1nQ08yX2dDIDwtIHRzJGdDX2dTICogdHMkZHdfZyAqIHRzJG1nQ08yX2phciAqICgxMi80NCkKdHMkbWdDTzJfZ0NfZCA8LSB0cyRtZ0NPMl9nQyAvIHRzJHRpbWVfZAoKIyBhdmVyYWdlIHJlcHMKdHMuYXZnIDwtIHRzICU+JQogIGdyb3VwX2J5KFBNZWNvLCB5ZWFyLCBkZXB0aCwgdGltZXBvaW50X2NtdHYpICU+JQogIHN1bW1hcml6ZSh0aW1lX2QgPSBtZWFuKHRpbWVfZCksCiAgICAgICAgICAgIG1nQ08yX2dDX2RfYXZnID0gbWVhbihtZ0NPMl9nQ19kKSwKICAgICAgICAgICAgbWdDTzJfZ0NfZF9tYXggPSBtYXgobWdDTzJfZ0NfZCksCiAgICAgICAgICAgIG1nQ08yX2dDX2RfbWluID0gbWluKG1nQ08yX2dDX2QpLAogICAgICAgICAgICBtZ0NPMl9nQ19hdmcgPSBtZWFuKG1nQ08yX2dDKSwKICAgICAgICAgICAgbWdDTzJfZ0NfbWF4ID0gbWF4KG1nQ08yX2dDKSwKICAgICAgICAgICAgbWdDTzJfZ0NfbWluID0gbWluKG1nQ08yX2dDKSkgJT4lCiAgbXV0YXRlKFBNZWNvX2RlcHRoX3llYXIgPSBwYXN0ZShQTWVjbywgZGVwdGgsIHllYXIsIHNlcCA9ICJfIikpCgojIGFkZCBkZXB0aCBpbmRleAp0MSA8LSB0cy5hdmdbdHMuYXZnJHRpbWVwb2ludF9jbXR2ID09IDEsIF0KdDEgPC0gZGF0YS5mcmFtZSgKICBiaW5kX3Jvd3MoCiAgICBsYXBwbHkoc3BsaXQodDEsIHQxJHllYXIpLCBmdW5jdGlvbihkZikgewogICAgICBiaW5kX3Jvd3MobGFwcGx5KHNwbGl0KGRmLCBkZiRQTWVjbyksIGZ1bmN0aW9uKHgpIHsKICAgICAgICB4JGx5cl90b3AgPC0gYXMubnVtZXJpYyhzYXBwbHkoc3Ryc3BsaXQoeCRkZXB0aCwgIi0iKSwgIlsiLCAxKSkKICAgICAgICB4IDwtIHhbb3JkZXIoeCRseXJfdG9wKSwgXQogICAgICAgIHgkZGVwdGhfaW5kZXggPC0gc2VxKDEsIG5yb3coeCkpCiAgICAgICAgcmV0dXJuKHgpCiAgICAgIH0pKQogICAgfSkpKQp0cy5hdmckZGVwdGhfaW5kZXggPC0gdDFbbWF0Y2godHMuYXZnJFBNZWNvX2RlcHRoX3llYXIsIHQxJFBNZWNvX2RlcHRoX3llYXIpLCAiZGVwdGhfaW5kZXgiXQpgYGAKCmBgYHtyIHBsb3QtcmVzcC1yYXRlc30KZmlnLm4gPC0gMQojIGZ1bmN0aW9uIGZvciBwbG90dGluZwp0cy5wbG90LmZ4IDwtIGZ1bmN0aW9uKGRmLCB5ciwgaW5jcmVtZW50LCBjdW11bGF0aXZlID0gVFJVRSkgewogICAgICBpZiAoY3VtdWxhdGl2ZSkgewogICAgICAgIGRmICU+JQogICAgICAgICAgZmlsdGVyKHllYXIgPT0geXIgJiBkZXB0aF9pbmRleCA9PSBpbmNyZW1lbnQpICU+JQogICAgICAgICAgbXV0YXRlKFBNID0gaWZlbHNlKGdyZXBsKCJBTiIsIFBNZWNvKSwgIkFOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkJTIiwgUE1lY28pLCAiQlMiLCAiR1IiKSksCiAgICAgICAgICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShncmVwbCgicmYiLCBQTWVjbyksICJyZiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJ3ZiIsIFBNZWNvKSwgIndmIiwgInBwIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgICAgICAgICBnZ3Bsb3QoLiwgYWVzKHRpbWVfZCwgbWdDTzJfZ0NfYXZnLCBjb2xvciA9IFBNLCBzaGFwZSA9IGVjbykpICsKICAgICAgICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gbWdDTzJfZ0NfbWF4LCB5bWF4ID0gbWdDTzJfZ0NfbWluLCBmaWxsID0gUE0sIGxpbmV0eXBlID0gZWNvLCBhbHBoYSA9IDAuMiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHRpbWVfZCwgbWdDTzJfZ0NfbWF4LCBmaWxsID0gUE0sIHNoYXBlID0gZWNvKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgc3Ryb2tlID0gMSkgKwogICAgICAgICAgZ2VvbV9wb2ludChhZXModGltZV9kLCBtZ0NPMl9nQ19taW4sIGZpbGwgPSBQTSwgc2hhcGUgPSBlY28pLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzLCBzdHJva2UgPSAxKSArCiAgICAgICAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gUE0sIGxpbmV0eXBlID0gZWNvKSwgc2l6ZSA9IDEuMikgKwogICAgICAgICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLAogICAgICAgICAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKGVjbyA9IGMoInJmIiA9ICJjb2xkIiwgIndmIiA9ICJjb29sIiwgInBwIiA9ICJ3YXJtIikpKSArCiAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDMwKSkgKwogICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiQU4iID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICAgICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInJmIiA9ICJjb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAiY29vbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHAiID0gIndhcm0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJwcCIgPSAyMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmYiID0gMjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9IDI0KSkgKwogICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID1jKCJBTiIgPSAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSkgKwogICAgICAgICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmYiID0gImRvdHRlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gImRhc2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHAiID0gInNvbGlkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygicmYiID0gImNvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9ICJjb29sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcCIgPSAid2FybSIpKSArCiAgICAgICAgICB5bGFiKGV4cHJlc3Npb24oJ0N1bXVsYXRpdmUgZmx1eCAobWdDTydbMl0qJy1DIGdDJ14tMSonKScpKSArCiAgICAgICAgICB4bGFiKCJUaW1lIChkYXlzKSIpICsKICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDEpLAogICAgICAgICAgICAgICAgIHNoYXBlID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMykpICsKICAgICAgICAgIGdndGl0bGUocGFzdGUoIkN1bXVsYXRpdmUgZmx1eCwgIiwgeXIsICJkZXB0aCAiLCBpbmNyZW1lbnQpKSArCiAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCiAgICB9IGVsc2UgewogICAgICAgZGYgJT4lCiAgICAgICAgZmlsdGVyKHllYXIgPT0geXIgJiBkZXB0aF9pbmRleCA9PSBpbmNyZW1lbnQpICU+JQogICAgICAgIG11dGF0ZShQTSA9IGlmZWxzZShncmVwbCgiQU4iLCBQTWVjbyksICJBTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiQlMiLCBQTWVjbyksICJCUyIsICJHUiIpKSwKICAgICAgICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKGdyZXBsKCJyZiIsIFBNZWNvKSwgInJmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgid2YiLCBQTWVjbyksICJ3ZiIsICJwcCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogICAgICAgIGdncGxvdCguLCBhZXModGltZV9kLCBtZ0NPMl9nQ19kX2F2ZywgY29sb3IgPSBQTSwgc2hhcGUgPSBlY28pKSArCiAgICAgICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBtZ0NPMl9nQ19kX21heCwgeW1heCA9IG1nQ08yX2dDX2RfbWluLCBmaWxsID0gUE0sIGxpbmV0eXBlID0gZWNvLCBhbHBoYSA9IDAuMiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHRpbWVfZCwgbWdDTzJfZ0NfZF9tYXgsIGZpbGwgPSBQTSwgc2hhcGUgPSBlY28pLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzLCBzdHJva2UgPSAxKSArCiAgICAgICAgICBnZW9tX3BvaW50KGFlcyh0aW1lX2QsIG1nQ08yX2dDX2RfbWluLCBmaWxsID0gUE0sIHNoYXBlID0gZWNvKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgc3Ryb2tlID0gMSkgKwogICAgICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBQTSwgbGluZXR5cGUgPSBlY28pLCBzaXplID0gMS4yKSArCiAgICAgICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLAogICAgICAgICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihlY28gPSBjKCJyZiIgPSAiY29sZCIsICJ3ZiIgPSAiY29vbCIsICJwcCIgPSAid2FybSIpKSkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMzApKSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygicmYiID0gImNvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAiY29vbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBwIiA9ICJ3YXJtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInBwIiA9IDIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmYiID0gMjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAyNCkpICsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPWMoIkFOIiA9ICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICAgICAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmYiID0gImRvdHRlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9ICJkYXNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcCIgPSAic29saWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygicmYiID0gImNvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAiY29vbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBwIiA9ICJ3YXJtIikpICsKICAgICAgICB5bGFiKGV4cHJlc3Npb24oJ1Jlc3BpcmF0aW9uIFJhdGUgKG1nQ08nWzJdKictQyBnQydeLTEqJ2QnXi0xKicpJykpICsKICAgICAgICB4bGFiKCJUaW1lIChkYXlzKSIpICsKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAxKSwKICAgICAgICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAzKSkgKwogICAgICAgIGdndGl0bGUocGFzdGUoIkZsdXggcmF0ZSIsIHlyLCAiZGVwdGggIiwgaW5jcmVtZW50KSkgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCiAgICB9Cn0KCiMjIGN1bXVsYXRpdmUgZmx1eAojIDIwMTkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMTkiLCBpbmNyZW1lbnQgPSAiMSIpCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDE5IiwgaW5jcmVtZW50ID0gIjIiKQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAxOSIsIGluY3JlbWVudCA9ICIzIikKIyAyMDAxCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDAxIiwgaW5jcmVtZW50ID0gIjEiKQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAwMSIsIGluY3JlbWVudCA9ICIyIikKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMDEiLCBpbmNyZW1lbnQgPSAiMyIpCgojIyBmbHV4IHJhdGVzCiMgMjAxOQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAxOSIsIGluY3JlbWVudCA9ICIxIiwgY3VtdWxhdGl2ZSA9IEZBTFNFKQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAxOSIsIGluY3JlbWVudCA9ICIyIiwgY3VtdWxhdGl2ZSA9IEZBTFNFKQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAxOSIsIGluY3JlbWVudCA9ICIzIiwgY3VtdWxhdGl2ZSA9IEZBTFNFKQojIDIwMDEKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMDEiLCBpbmNyZW1lbnQgPSAiMSIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMDEiLCBpbmNyZW1lbnQgPSAiMiIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMDEiLCBpbmNyZW1lbnQgPSAiMyIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIFJlc3BpcmF0aW9uIGRhdGEgZnJvbSBpbmN1YmF0aW9ucyBvZiAyMDE5IGFuZCAyMDAxIGJ1bGsgc29pbHMuICoqCgo+KkNhcHRpb246KiBQb2ludHMgc2hvdyBtZWFzdXJlZCBDT34yfiBwcm9kdWN0aW9uIG9mIGxhYm9yYXRvcnkgZHVwbGljYXRlcyBhcyBjdW11bGF0aXZlIGZsdXhlcyBvciBkYWlseSBmbHV4IHJhdGVzIGJ5IGRlcHRoLCBsaW5lcyBzaG93IHRoZSBtZWFucywgYW5kIHRoZSByaWJib24gcmVwcmVzZW50cyB0aGUgcmFuZ2UuIAoKKk1lcmdlIHRlbXBsYXRlcyB3aXRoIDE0QywgQywgYW5kIE4gZGF0YSoKClJhZGlvY2FyYm9uIGFuYWx5c2VzIGZvciB0aGUgMjAwMSBzYW1wbGVzIHdlcmUgbm90IHJ1biBvcmlnaW5hbGx5LCBidXQgd2VyZSBjb21wbGV0ZWQgb24gYXJjaGl2ZWQgc2FtcGxlcyBpbiAyMDIwLgoKYGBge3IgbWVyZ2UtaXNvLWRhdGEtUzAxLXNvaWx9CiMgRXh0cmFjdCAxNEMgZGF0YSBmb3IgMjAwMSBzYW1wbGVzCmFtc19yZXN1bHRzX2xzX1MwMSA8LSBhbXNfcmVzdWx0c19sc1tncmVwKCJTMDEiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEpKSB7CiAgc3JhLjIwMDFbW2ldXSA8LSBsYXBwbHkoYW1zX3Jlc3VsdHNfbHNfUzAxLCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMDEpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDAxKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMDFbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMDFbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDAxIDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMDEsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMgY3JlYXRlIElEIGZpZWxkLCB0cmltIGRmLCBhbmQgYWRkIGRlcHRocwpzcmEuMjAwMSRJRCA8LSB1bmxpc3Qoc3Ryc3BsaXQoc3JhLjIwMDEkUHJvYmUsICJfU2llcnJhIE5ldmFkYV8yMDAxIikpCnNyYS4yMDAxIDwtIHNyYS4yMDAxWyAsIGMoIklEIiwgIkYxNEMiLCAiZXJyIiwgIuKIhjE0Qy4o4oCwKSIsICJlcnIuKOKAsCkiKV0KbmFtZXMoc3JhLjIwMDEpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKc3JhLjIwMDEkbHlyX3RvcCA8LSBhcy5udW1lcmljKGlmZWxzZShzdWJzdHIoc3JhLjIwMDEkSUQsIDksIDkpID09ICItIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIoc3JhLjIwMDEkSUQsIDgsIDgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnN0cihzcmEuMjAwMSRJRCwgOCwgOSkpKQpzcmEuMjAwMSRseXJfYm90IDwtIGFzLm51bWVyaWMoaWZlbHNlKHN1YnN0cihzcmEuMjAwMSRJRCwgOSwgOSkgPT0gIi0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIoc3JhLjIwMDEkSUQsIDEwLCBuY2hhcihzcmEuMjAwMSRJRCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnN0cihzcmEuMjAwMSRJRCwgMTEsIG5jaGFyKHNyYS4yMDAxJElEKSkpKQpzcmEuMjAwMSRwcm9fcmVwIDwtIHN1YnN0cihzcmEuMjAwMSRJRCwgNiwgNikKc3JhLjIwMDEkUE0gPC0gZmFjdG9yKHN1YnN0cihzcmEuMjAwMSRJRCwgMSwgMikpCnNyYS4yMDAxJEVDTyA8LSBmYWN0b3Ioc3Vic3RyKHNyYS4yMDAxJElELCAzLCA0KSwgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkKc3JhLjIwMDEkcHJvX25hbWUgPC0gc3Vic3RyKHNyYS4yMDAxJElELCAxLCA2KQpzcmEuMjAwMSRQTWVjbyA8LSBzdWJzdHIoc3JhLjIwMDEkSUQsIDEsIDQpCgojIHJlbW92ZSBvdXRsaWVyIEFOcHAgc2FtcGxlCnNyYS4yMDAxIDwtIHNyYS4yMDAxWy13aGljaChzcmEuMjAwMSRJRCA9PSAiQU5wcF8zXzYtMTMiKSwgXQoKIyBtYWtlIGxpc3QgYnkgUE1lY28Kc3JhLjIwMDEubHMgPC0gc3BsaXQoc3JhLjIwMDEsIHNyYS4yMDAxJFBNZWNvKQpgYGAKCmBgYHtyIG1lcmdlLWlzby1kYXRhLXNvaWwtUzE5fQojIEV4dHJhY3QgMTRDIGRhdGEgZm9yIDIwMTkgc2FtcGxlcwphbXNfcmVzdWx0c19sc19TMTkgPC0gYW1zX3Jlc3VsdHNfbHNbZ3JlcCgic29pbC1TMTkiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMTkpKSB7CiAgc3JhLjIwMTlbW2ldXSA8LSBsYXBwbHkoYW1zX3Jlc3VsdHNfbHNfUzE5LCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDE5KVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTlbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMTlbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDE5IDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMTksIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMjIG1lcmdlIHcvIDIwMTkgdGVtcGxhdGUKIyByZW5hbWUgY29scyBpbiBBTVMgdGFibGVzCnNyYS4yMDE5IDwtIHNyYS4yMDE5WyAsIGMoIlByb2JlIiwgIkYxNEMiLCAiZXJyIiwgIuKIhjE0Qy4o4oCwKSIsICJlcnIuKOKAsCkiKV0KbmFtZXMoc3JhLjIwMTkpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKIyBtZXJnZQpzcmEuMjAxOS5scyA8LSBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuZGYsIHNyYS4yMDE5LmRmJGx5cl9uYW1lKSwgZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBtZXJnZShkZiwgc3JhLjIwMTlbZ3JlcChkZiRseXJfbmFtZSwgc3JhLjIwMTkkSUQpLCBdKQogIGRmJElEIDwtIE5VTEwKICBkZiRQTWVjbyA8LSBwYXN0ZTAoZGYkUE0sIGRmJEVDTykKICByZXR1cm4oZGYpCn0pCgojIHJlc2hhcGUgbGlzdCBieSBQTWVjbwpzcmEuMjAxOS5scyA8LSBzcGxpdChiaW5kX3Jvd3Moc3JhLjIwMTkubHMpLCBiaW5kX3Jvd3Moc3JhLjIwMTkubHMpW1siUE1lY28iXV0pCmBgYAoKYGBge3IgbWVyZ2UtaXNvLWRhdGEtY28yfQojIyMgRXh0cmFjdCAxNEMgZGF0YSBmb3IgaW5jdWJhdGlvbiBzYW1wbGVzCiMjIHJlc3BpcmVkIENPMiwgc29pbAojIDIwMTkKYW1zX3Jlc3VsdHNfbHNfY28yX1MxOSA8LSBhbXNfcmVzdWx0c19sc1tncmVwKCJjbzItUzE5IiwgbmFtZXMoYW1zX3Jlc3VsdHNfbHMpKV0KZm9yIChpIGluIHNlcV9hbG9uZyhzcmEuMjAxOS5pbmMpKSB7CiAgc3JhLjIwMTkuaW5jW1tpXV0gPC0gbGFwcGx5KGFtc19yZXN1bHRzX2xzX2NvMl9TMTksIGZ1bmN0aW9uKGxzKSB7CiAgICBsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSB7CiAgICAgIGlmIChhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkuaW5jKVtpXSwgZGYkUHJvYmUpKSkgewogICAgICAgIGRmW2dyZXAobmFtZXMoc3JhLjIwMTkuaW5jKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTkuaW5jW1tpXV0gPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgdW5saXN0KHNyYS4yMDE5LmluY1tbaV1dLCByZWN1cnNpdmUgPSBGQUxTRSkpCn0Kc3JhLjIwMTkuaW5jIDwtIHR5cGUuY29udmVydCgKICBiaW5kX3Jvd3MoCiAgICBsYXBwbHkodW5saXN0KHNyYS4yMDE5LmluYywgcmVjdXJzaXZlID0gRkFMU0UpLCAKICAgICAgICAgICBmdW5jdGlvbih4KSB4ICU+JSBtdXRhdGVfYWxsKGFzLmNoYXJhY3RlcikpKSwKICBhcy5pcyA9IFRSVUUpCnNyYS4yMDE5LmluYyA8LSBzcmEuMjAxOS5pbmNbLXdoaWNoKGlzLm5hKHNyYS4yMDE5LmluYyRGMTRDKSksIF0KCiMgMjAwMQphbXNfcmVzdWx0c19sc19jbzJfUzAxIDwtIGFtc19yZXN1bHRzX2xzW2dyZXAoImNvMi1TMDEiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQojIHJlbW92ZSBxdWVzdGlvbmFibGUvZHVwbGljYXRlIHNhbXBsZXMKIyBBTnJmX2NvbXBfMTEtMzJfMjAwMV9hIChhbmFseXplZCB0d2ljZTsgYm90aCBhbm9tb3VzbHkgbG93IGNvbXBhcmVkIHRvIHJlcCBhbmQgcmVzdCBvZiBkYXRhKQphbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIyLnhsc3hgIDwtIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIwLTEyLTExYCRgQmVlbS1NaWxsZXJfMjIueGxzeGBbLWdyZXAoIkFOcmZfY29tcF8xMS0zMl8yMDAxX2EiLCBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIyLnhsc3hgJFByb2JlKSwgXQphbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xNmAkYDE0Q19TaWVycmFOZXZhZGFfSW5jXzIwMDFfM19yZXN1bHRzLnhsc3hgIDwtIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIwLTEyLTE2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8zX3Jlc3VsdHMueGxzeGBbLWdyZXAoIkFOcmZfY29tcF8xMS0zMl8yMDAxX2EiLCBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xNmAkYDE0Q19TaWVycmFOZXZhZGFfSW5jXzIwMDFfM19yZXN1bHRzLnhsc3hgJFByb2JlKSwgXQojIGZyb20gb3JpZ2luYWwgYW5hbHlzaXMgb2Ygc2FtcGxlcyBleHRyYWN0ZWQgb25saW5lIDExLURlYy0yMDIwIChzZWUgcmVhZG1lIGZvciBub3RlcykKYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjAtMTItMTFgJGBCZWVtLU1pbGxlcl8yMy54bHN4YCA8LSBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIzLnhsc3hgWy1ncmVwKCJHUndmX2NvbXBfMTMtMjhfMjAwMV9hXzExIiwgYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YCRQcm9iZSksIF0KIyBmcm9tIHJlYW5hbHlzaXMgb2Ygc2FtcGxlcyBleHRyYWN0ZWQgb25saW5lIDExLURlYy0yMDIwIChzZWUgcmVhZG1lIGZvciBub3RlcykKIyBHUnJmX2NvbXBfOC0yN18yMDAxX2FfNSwgR1JyZl9jb21wXzgtMjdfMjAwMV9iXzYsIEdScHBfY29tcF8xNS0yN18yMDAxX2JfMTggCmFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIxLTAxLTI2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8yX3Jlc3VsdHMueGxzeGAgPC0gYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YFtjKAogIGdyZXAoIkdScmZfY29tcF84LTI3XzIwMDFfYV81IiwgYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YCRQcm9iZSksCiAgZ3JlcCgiR1J3Zl9jb21wXzEzLTI4XzIwMDFfYl8xMiIsIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIxLTAxLTI2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8yX3Jlc3VsdHMueGxzeGAkUHJvYmUpKSwgXQoKIyBjcmVhdGUgdGVtcGxhdGUgZm9yIGV4dHJhY3RpbmcgZGF0YQpzcmEuMjAwMS5pbmMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aCh1bmlxdWUoc3JhLjIwMTkuaW5jLmRmJHByb19uYW1lKSkpCm5hbWVzKHNyYS4yMDAxLmluYykgPC0gdW5pcXVlKHNyYS4yMDE5LmluYy5kZiRwcm9fbmFtZSkKIyBtZXJnZSB3aXRoIDE0QyBkYXRhCmZvciAoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEuaW5jKSkgewogIHNyYS4yMDAxLmluY1tbaV1dIDwtIGxhcHBseShhbXNfcmVzdWx0c19sc19jbzJfUzAxLCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZiAoYW55KGdyZXBsKG5hbWVzKHNyYS4yMDAxLmluYylbaV0sIGRmJFByb2JlKSkpIHsKICAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDAxLmluYylbaV0sIGRmJFByb2JlKSwgXSAKICAgICAgfQogICAgfSkKICB9KQogIHNyYS4yMDAxLmluY1tbaV1dIDwtIEZpbHRlcihOZWdhdGUoaXMubnVsbCksIHVubGlzdChzcmEuMjAwMS5pbmNbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDAxLmluYyA8LSB0eXBlLmNvbnZlcnQoCiAgYmluZF9yb3dzKAogICAgbGFwcGx5KHVubGlzdChzcmEuMjAwMS5pbmMsIHJlY3Vyc2l2ZSA9IEZBTFNFKSwgCiAgICAgICAgICAgZnVuY3Rpb24oeCkgeCAlPiUgbXV0YXRlX2FsbChhcy5jaGFyYWN0ZXIpKSksCiAgYXMuaXMgPSBUUlVFKQpzcmEuMjAwMS5pbmMgPC0gc3JhLjIwMDEuaW5jWy13aGljaChpcy5uYShzcmEuMjAwMS5pbmMkRjE0QykpLCBdCgojIHJlc3BpcmVkIENPMiwgbGl0dGVyCmFtc19yZXN1bHRzX2xzX2NvMl9MMTkgPC0gYW1zX3Jlc3VsdHNfbHNbZ3JlcCgiY28yLUwxOSIsIG5hbWVzKGFtc19yZXN1bHRzX2xzKSldCmZvcihpIGluIHNlcV9hbG9uZyhzcmEuMjAxOS5pbmNfTCkpIHsKICBzcmEuMjAxOS5pbmNfTFtbaV1dIDwtIGxhcHBseShhbXNfcmVzdWx0c19sc19jbzJfTDE5LCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkuaW5jX0wpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDE5LmluY19MKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTkuaW5jX0xbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMTkuaW5jX0xbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDE5LmluY19MIDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMTkuaW5jX0wsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMjIG1lcmdlIHcvIHRlbXBsYXRlcyBbd2h5IGRvIEkgZG8gdGhpcyB0d2ljZT9dCiMgcmVuYW1lIGNvbHMgaW4gQU1TIHRhYmxlcwojIHNvaWwgQ08yCnNyYS4yMDE5LmluYyA8LSBzcmEuMjAxOS5pbmNbICwgYygiUHJvYmUiLCAiRjE0QyIsICJlcnIiLCAi4oiGMTRDLijigLApIiwgImVyci4o4oCwKSIpXQpuYW1lcyhzcmEuMjAxOS5pbmMpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKc3JhLjIwMDEuaW5jIDwtIHNyYS4yMDAxLmluY1sgLCBjKCJQcm9iZSIsICJGMTRDIiwgImVyciIsICLiiIYxNEMuKOKAsCkiLCAiZXJyLijigLApIildCm5hbWVzKHNyYS4yMDAxLmluYykgPC0gYygiSUQiLCAiZm0iLCAiZm1fZXJyIiwgImQxNGMiLCAiZDE0Y19lcnIiKQojIG1lcmdlCiMgMjAxOQpzcmEuMjAxOS5pbmMubHMgPC0gYmluZF9yb3dzKAogIGxhcHBseShzcGxpdChzcmEuMjAxOS5pbmMuZGYsIHNyYS4yMDE5LmluYy5kZiRseXJfbmFtZSksIGZ1bmN0aW9uKGRmKSB7CiAgICBkZiA8LSBtZXJnZShkZiwgc3JhLjIwMTkuaW5jW2dyZXAoZGYkbHlyX25hbWUsIHNyYS4yMDE5LmluYyRJRCksIF0pCiAgICBkZiRJRCA8LSBOVUxMCiAgICBkZiRQTWVjbyA8LSBwYXN0ZTAoZGYkUE0sIGRmJEVDTykKICAgIHJldHVybihkZikKICB9KQopCnNyYS4yMDE5LmluYy5scyA8LSBzcGxpdChzcmEuMjAxOS5pbmMubHMsIHNyYS4yMDE5LmluYy5scyRQTWVjbykKIyAyMDAxCnNyYS4yMDAxLmluYy5scyA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmluYy5kZiwgc3JhLjIwMDEuaW5jLmRmJGx5cl9uYW1lKSwgZnVuY3Rpb24oZGYpIHsKICAgIGRmIDwtIG1lcmdlKGRmLCBzcmEuMjAwMS5pbmNbZ3JlcChkZiRseXJfbmFtZSwgc3JhLjIwMDEuaW5jJElEKSwgXSkKICAgIGRmJElEIDwtIE5VTEwKICAgIGRmJFBNZWNvIDwtIHBhc3RlMChkZiRQTSwgZGYkRUNPKQogICAgcmV0dXJuKGRmKQogIH0pCikKc3JhLjIwMDEuaW5jLmxzIDwtIHNwbGl0KHNyYS4yMDAxLmluYy5scywgc3JhLjIwMDEuaW5jLmxzJFBNZWNvKQoKCiMgbGl0dGVyIENPMgpzcmEuMjAxOS5pbmNfTCA8LSBzcmEuMjAxOS5pbmNfTFsgLCBjKCJQcm9iZSIsICJGMTRDIiwgImVyciIsICLiiIYxNEMuKOKAsCkiLCAiZXJyLijigLApIildCm5hbWVzKHNyYS4yMDE5LmluY19MKSA8LSBjKCJJRCIsICJmbSIsICJmbV9lcnIiLCAiZDE0YyIsICJkMTRjX2VyciIpCnNyYS4yMDE5LmluY19MJElEIDwtIHN1YnN0cihzdWJzdHJpbmcoc3JhLjIwMTkuaW5jX0wkSUQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2V4cHIoIl8iLCBzcmEuMjAxOS5pbmNfTCRJRCkgKyAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY2hhcihzcmEuMjAxOS5pbmNfTCRJRCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwgOCkKc3JhLjIwMTkuaW5jLmRmX0wgPC0gZGF0YS5mcmFtZShZZWFyID0gcmVwKDIwMTksIDE4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAgPSByZXAoYygxLCAyKSwgOSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUE0gPSByZXAoYygiQU4iLCAiQlMiLCAiR1IiKSwgZWFjaCA9IDYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjbyA9IHJlcChjKCJwcCIsICJ3ZiIsICJyZiIpLCBlYWNoID0gMiwgdGltZXMgPSAzKSkKc3JhLjIwMTkuaW5jLmRmX0wkUE1lY28gPC0gcGFzdGUwKHNyYS4yMDE5LmluYy5kZl9MJFBNLCBzcmEuMjAxOS5pbmMuZGZfTCRlY28pCnNyYS4yMDE5LmluYy5kZl9MJElEIDwtIHBhc3RlMChzcmEuMjAxOS5pbmMuZGZfTCRQTSwgc3JhLjIwMTkuaW5jLmRmX0wkZWNvLCAiLUxfIiwgc3JhLjIwMTkuaW5jLmRmX0wkcmVwKQojIGFkZCBkcnkgd3RzIGFuZCBsaXR0ZXIgZGVwdGgKc3JhLjIwMTkuTCA8LSByZWFkLmNzdigiLi4vZGF0YS9kZXJpdmVkL2xhYl9qZW5hX2xpdHRlci9MaXR0ZXJfMjAxOV8yMDIxLTAxLTI3LmNzdiIpCnNyYS4yMDE5LmluYy5kZl9MIDwtIG1lcmdlKHNyYS4yMDE5LmluYy5kZl9MLCBzcmEuMjAxOS5MWyAsIGMoIlBNZWNvIiwgImx5cl90b3AiLCAibHlyX2JvdCIpXSwgYWxsLnggPSBUUlVFKQojIG1lcmdlCnNyYS4yMDE5LmluY19MLmRmIDwtIGJpbmRfcm93cygKICBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuaW5jX0wsIHNyYS4yMDE5LmluY19MJElEKSwgZnVuY3Rpb24oZGYpIHsKICAgIGRmIDwtIG1lcmdlKGRmLCBzcmEuMjAxOS5pbmMuZGZfTCwgYnkgPSAiSUQiKQogICAgZGYkSUQgPC0gTlVMTAogICAgcmV0dXJuKGRmKQogIH0pCikKc3JhLjIwMTkuaW5jX0wubHMgPC0gc3BsaXQoc3JhLjIwMTkuaW5jX0wuZGYsIHNyYS4yMDE5LmluY19MLmRmJFBNZWNvKQpgYGAKCmBgYHtyIHBsb3QtdXRpbHN9CiMgZm0gYW5kIGQxNGMgY29udmVyc2lvbiBmdW5jdGlvbnMKbGFtYmRhIDwtIDEvODI2NyAjID0gMS8odHJ1ZSBtZWFuIGxpZmUgb2YgMTRDKQpjYWxjX2ZtIDwtIGZ1bmN0aW9uKGQxNGMsIG9ic19kYXRlX3kpIHsKICAoKGQxNGMvMTAwMCkgKyAxKS9leHAobGFtYmRhICogKDE5NTAgLSBvYnNfZGF0ZV95KSkKfQpjYWxjXzE0YyA8LSBmdW5jdGlvbihmbSwgb2JzX2RhdGVfeSkgewogIChmbSAqIGV4cChsYW1iZGEgKiAoMTk1MCAtIG9ic19kYXRlX3kpKSAtIDEpICogMTAwMAp9CgojIGNhbGMgYXRtIGluIDIwMDEsIDIwMDksIDIwMTkKRGF0bSA8LSByYmluZChncmF2ZW4sIGZ1dHVyZTE0QykKYXRtLmQxNC4yMDAxIDwtIERhdG1bRGF0bSREYXRlID09IDIwMDEuNSwgIk5IYzE0Il0KYXRtLmZtLjIwMDEgPC0gY2FsY19mbShhdG0uZDE0LjIwMDEsIDIwMDEpCmF0bS5kMTQuMjAwOSA8LSBEYXRtW0RhdG0kRGF0ZSA9PSAyMDA5LjUsICJOSGMxNCJdCmF0bS5mbS4yMDA5IDwtIGNhbGNfZm0oYXRtLmQxNC4yMDA5LCAyMDA5KQphdG0uZDE0LjIwMTkgPC0gRGF0bVtEYXRtJERhdGUgPT0gMjAxOS41LCAiTkhjMTQiXQphdG0uZm0uMjAxOSA8LSBjYWxjX2ZtKGF0bS5kMTQuMjAxOSwgMjAxOSkKYGBgCgpgYGB7ciBwbG90LWxpdHRlci0xNGN9CmZpZy5uIDwtIGZpZy5uICsgMQojIHN1bW1hcml6ZSBsaXR0ZXIgaW5jIGRhdGEKc3JhLjIwMTkuaW5jX0wuc3VtIDwtIHNyYS4yMDE5LmluY19MLmRmICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKGVjbyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVjbyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIHBtID0gZmFjdG9yKGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpKSwKICAgICAgICAgWWVhciA9IGZhY3RvcigiMjAxOSIpKSAlPiUKICBncm91cF9ieShZZWFyLCBwbSwgZWNvLCBseXJfdG9wLCBseXJfYm90KSAlPiUKICBzdW1tYXJpemUoZDE0Y19tZWFuID0gbWVhbihkMTRjKSwKICAgICAgICAgICAgZDE0Y191ID0gbWF4KGQxNGMpLAogICAgICAgICAgICBkMTRjX2wgPSBtaW4oZDE0YykpCgojIHBsb3QgYXMgY29scyBieSBjbGltYXRlCnNyYS4yMDE5LmluY19MLnN1bSAlPiUKICBtdXRhdGUoTUFUID0gZmFjdG9yKGVjbywgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSwgbGFiZWxzID0gYygiMTAtMTMiLCAiOC0xMCIsICI1LTYiKSkpICU+JQogIGdncGxvdCguLCBhZXMoTUFULCBkMTRjX21lYW4sIGZpbGwgPSBwbSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UyIikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltYXggPSBkMTRjX3UsIHltaW4gPSBkMTRjX2wsIGNvbG9yID0gcG0pLCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UyKHdpZHRoID0gLjUsIHBhZGRpbmcgPSAuNSkpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgY29vcmRfZmxpcCgpICsKICB5bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbigiTUFUICgiKn5kZWdyZWUqQyoiKSIpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdCBhcyBwb2ludHMgd2l0aCBkZXB0aApzcmEuMjAxOS5pbmNfTC5zdW0gJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4sIGx5cl90b3AsIGNvbG9yID0gcG0pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtYXggPSBkMTRjX3UsIHhtaW4gPSBkMTRjX2wpLCBoZWlnaHQgPSAxKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbykpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIExpdHRlciBpbmN1YmF0aW9uICRcRGVsdGEkXjE0XkMtQ09+Mn4gKDIwMTkpKioKCj4qQ2FwdGlvbjoqIE1lYW4gJFxEZWx0YSReMTReQy1DT34yfiBmb3IgZWFjaCBzaXRlLiBFcnJvciBiYXJzIHNob3cgbWluIGFuZCBtYXggb2YgZHVwbGljYXRlIGluY3ViYXRpb24gc2FtcGxlcy4gXmEpXiBEYXRhIHNob3duIGJ5IHNpdGUsIHdpdGhvdXQgbGl0dGVyIGRlcHRoLCBeYileIERhdGEgc2hvd24gYnkgZGVwdGggb2YgbGl0dGVyIGxheWVyLCBiaW5uZWQgYnkgY2xpbWF0ZSB6b25lLgoKYGBge3IgcGxvdC0xNGMtcHJvZmlsZS1meH0KcHJvLnBsb3QgPC0gZnVuY3Rpb24oZGYsIG1heERlcHRoLCBtaW4xNEMsIHJlcCkgewogIGdncGxvdChkZiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gUE0sIHNoYXBlID0gRUNPLCBncm91cCA9IHJlcCkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICAgIGdlb21fcGF0aCgpICsKICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKG1heERlcHRoLCAwKSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMobWluMTRDLCAxODApKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImdyYW5pdGUiKSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiZWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJwcCIgPSBleHByZXNzaW9uKGl0YWxpYygiUC4gcG9uZGVyb3NhIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJmIiA9IGV4cHJlc3Npb24oaXRhbGljKCJBLiBtYWduaWZpY2EiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gZXhwcmVzc2lvbihpdGFsaWMoIkEuIGNvbmNvbG9yIikpKSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJwcCIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmYiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9IDE3KSkgKwogICAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICAgIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCn0KYGBgCgpgYGB7ciBwbG90LTIwMDEtcHJvZmlsZXN9CiMgbGFwcGx5KHNyYS4yMDAxLmxzLCBmdW5jdGlvbihkZikgcHJvLnBsb3QoZGYsIG1heChkZiRseXJfYm90KSwgbWluKGRmJGQxNGMpLCBkZiRwcm9fcmVwKSkKYGBgCgpgYGB7ciBwbG90LTIwMTktcHJvZmlsZXN9CiMgbGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgcHJvLnBsb3QoZGYsIG1heChkZiRseXJfYm90KSwgbWluKGRmJGQxNGMpLCBkZiRwcm9fcmVwKSkKYGBgCgpgYGB7ciBwbG90LTIwMTktY28yLXByb2ZpbGVzfQojIGxhcHBseShzcmEuMjAxOS5pbmMubHMsIGZ1bmN0aW9uKGRmKSBwcm8ucGxvdChkZiwgbWF4KGRmJGx5cl9ib3QpLCBtaW4oZGYkZDE0YyksIE5BKSkKYGBgCgojIyAyMDAxIG1lYW4gcmFkaW9jYXJib24gcHJvZmlsZXMKYGBge3IgcGxvdC0yMDAxLWF2Zy1wcm9maWxlc30KIyBjb21iaW5lIHJlcHMKc3JhLjIwMDEuc3VtLmxzICA8LSBsYXBwbHkoc3JhLjIwMDEubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShkZiAlPiUKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGx5cl9ib3QgPD0gNDApICU+JQogICAgICAgICAgICAgICAgICAgICBtdXRhdGUobHlyX3RvcF9jaCA9IGFzLmNoYXJhY3RlcihseXJfdG9wKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx5cl9ib3RfY2ggPSBhcy5jaGFyYWN0ZXIobHlyX2JvdCkpICU+JQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUE0sIEVDTywgUE1lY28sIGZtLCBkMTRjLCBseXJfdG9wX2NoLCBseXJfYm90X2NoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoUE0sIEVDTywgUE1lY28sIGx5cl90b3BfY2gsIGx5cl9ib3RfY2gpICU+JQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpLCBuYS5ybSA9IFRSVUUpKQogIG5hbWVzKGRmKSA8LSBjKCJQTSIsICJFQ08iLCAiUE1lY28iLCAibHlyX3RvcCIsICJseXJfYm90IiwgImZtIiwgImQxNGMiLCAiZm1fc2QiLCAiZDE0Y19zZCIpCiAgZGYkbHlyX3RvcCA8LSBhcy5udW1lcmljKGRmJGx5cl90b3ApCiAgZGYkbHlyX2JvdCA8LSBhcy5udW1lcmljKGRmJGx5cl9ib3QpCiAgZGYkZDE0Y191IDwtIGRmJGQxNGMgKyBkZiRkMTRjX3NkCiAgZGYkZDE0Y19sIDwtIGRmJGQxNGMgLSBkZiRkMTRjX3NkCiAgcmV0dXJuKGRmW29yZGVyKGRmJGx5cl9ib3QpLCBdKQp9KQpzcmEuMDEuc3VtIDwtIGJpbmRfcm93cyhzcmEuMjAwMS5zdW0ubHMpICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkKCiMgcGxvdApmaWcubiA8LSBmaWcubiArIDEKc3JhLjAxLnN1bSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBncm91cCA9IFBNZWNvKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAwMSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBnZW9tX3BhdGgoKSArCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoNDAsIDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwMCwgMTgwKSkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiZWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBNZWFuIHByb2ZpbGUgJFxEZWx0YSReMTReQyBmb3IgMjAwMSBzYW1wbGVzKioKCj4qQ2FwdGlvbjoqIE1lYW4gJFxEZWx0YSReMTReQyBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMDEuIEVycm9yIGJhcnMgc2hvdyDCsTEgc3RhbmRhcmQgZGV2aWF0aW9uLCBzb2xpZCB2ZXJ0aWNhbCBsaW5lIHNob3dzICRcRGVsdGEkXjE0XkMgb2YgdGhlIGF0bW9zcGhlcmUgaW4gdGhlIHllYXIgb2Ygc2FtcGxpbmcuCgojIyAyMDA5IHJhZGlvY2FyYm9uIHByb2ZpbGVzCmBgYHtyIHBsb3QtMjAwOS1wcm9maWxlc30KIyAyMDA5IGRhdGEgKGZyb20gQy4gUmFzbXVzc2VuKQpyYXMxOC5seXIgPC0gcmVhZC5jc3YoIi9Vc2Vycy9qZWZmL1IvMTRDb25zdHJhaW50L3Jhc18yMDE4LmNzdiIpCnJhczE4Lmx5ciRFQ08gPC0gZmFjdG9yKHJhczE4Lmx5ciRNQVNULCBsYWJlbHMgPSBjKCJyZiIsIndmIiwicHAiKSkKIyBhZGQgUE1lY28gY29sCnJhczE4Lmx5ciRFQ08gPC0gZmFjdG9yKHJhczE4Lmx5ciRNQVNULCBsYWJlbHMgPSBjKCJyZiIsIndmIiwicHAiKSkKcmFzMTgubHlyJFBNZWNvIDwtIHBhc3RlMChyYXMxOC5seXIkUE0sIHJhczE4Lmx5ciRFQ08pCgojIHN1bW1hcml6ZSAwOSBkYXRhCnNyYS4wOS5zdW0gPC0gcmFzMTgubHlyICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkKCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMDkuc3VtICU+JQogIGdncGxvdCguLCBhZXMobHlyXzE0YywgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBlY28sIGdyb3VwID0gUE1lY28pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDA5KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTAwLCAxODApKSArICAgIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJlY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDIpKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIFByb2ZpbGUgJFxEZWx0YSReMTReQyBmb3IgMjAwOSBzYW1wbGVzKioKCj4qQ2FwdGlvbjoqIFByb2ZpbGUgJFxEZWx0YSReMTReQyBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMDkuIFNvbGlkIHZlcnRpY2FsIGxpbmUgc2hvd3MgJFxEZWx0YSReMTReQyBvZiB0aGUgYXRtb3NwaGVyZSBpbiB0aGUgeWVhciBvZiBzYW1wbGluZy4gRXJyb3IgYmFycyBub3Qgc2hvd24gYXMgb25seSBhIHNpbmdsZSByZXBsaWNhdGUgcHJvZmlsZSB3YXMgYW5hbHl6ZWQgcGVyIHNpdGUuCgojIyAyMDE5IG1lYW4gcmFkaW9jYXJib24gcHJvZmlsZXMKYGBge3IgcGxvdC0yMDE5LWF2Zy1wcm9maWxlc30KIyBjb21iaW5lIHJlcHMKc3JhLjIwMTkuc3VtLmxzICA8LSBsYXBwbHkoc3JhLjIwMTkubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShkZiAlPiUKICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGx5cl90b3BfY2ggPSBhcy5jaGFyYWN0ZXIobHlyX3RvcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBseXJfYm90X2NoID0gYXMuY2hhcmFjdGVyKGx5cl9ib3QpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFBNLCBFQ08sIFBNZWNvLCBmbSwgZDE0YywgbHlyX3RvcF9jaCwgbHlyX2JvdF9jaCkgJT4lCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KFBNLCBFQ08sIFBNZWNvLCBseXJfdG9wX2NoLCBseXJfYm90X2NoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSwgbmEucm0gPSBUUlVFKSkKICBuYW1lcyhkZikgPC0gYygiUE0iLCAiRUNPIiwgIlBNZWNvIiwgImx5cl90b3AiLCAibHlyX2JvdCIsICJmbSIsICJkMTRjIiwgImZtX3NkIiwgImQxNGNfc2QiKQogIGRmJGx5cl90b3AgPC0gYXMubnVtZXJpYyhkZiRseXJfdG9wKQogIGRmJGx5cl9ib3QgPC0gYXMubnVtZXJpYyhkZiRseXJfYm90KQogIGRmJGQxNGNfdSA8LSBkZiRkMTRjICsgZGYkZDE0Y19zZAogIGRmJGQxNGNfbCA8LSBkZiRkMTRjIC0gZGYkZDE0Y19zZAogIHJldHVybihkZikKfSkKc3JhLjE5LnN1bSA8LSBiaW5kX3Jvd3Moc3JhLjIwMTkuc3VtLmxzKSAlPiUKICBtdXRhdGUoZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpIAoKIyBwbG90CmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMTkuc3VtICU+JQogIGdncGxvdCguLCBhZXMoZDE0YywgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBlY28sIGdyb3VwID0gUE1lY28pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgZ2VvbV9wYXRoKCkgKwogIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKG1heChzcmEuMTkuc3VtJGx5cl9ib3QpLCAwKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKG1pbihzcmEuMTkuc3VtJGQxNGMpLCAxODApKSArICAgIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJlY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQiID0gMTcpKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIE1lYW4gcHJvZmlsZSAkXERlbHRhJF4xNF5DIGZvciAyMDE5IHNhbXBsZXMqKgoKPipDYXB0aW9uOiogTWVhbiAkXERlbHRhJF4xNF5DIGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAxOS4gRXJyb3IgYmFycyBzaG93IMKxMSBzdGFuZGFyZCBkZXZpYXRpb24sIHNvbGlkIHZlcnRpY2FsIGxpbmUgc2hvd3MgJFxEZWx0YSReMTReQyBvZiB0aGUgYXRtb3NwaGVyZSBpbiB0aGUgeWVhciBvZiBzYW1wbGluZy4KCiMjIENoYW5nZSBpbiAkXERlbHRhJF4xNF5DIG92ZXIgdGltZSBiZXR3ZWVuIDIwMDEgYW5kIDIwMTkgCgpgYGB7ciBwbG90LWFsbC1hdmd9CiMgY29tYmluZSAnMDEgYW5kICcxOSBkYXRhIGZvciBwbG90dGluZwpzcmEuMDEuc3VtJFllYXIgPC0gMjAwMQpzcmEuMTkuc3VtJFllYXIgPC0gMjAxOQoKc3JhLmFsbCA8LSByYmluZChzcmEuMDEuc3VtLCBzcmEuMTkuc3VtKQpzcmEuYWxsJFllYXIgPC0gYXMuZmFjdG9yKHNyYS5hbGwkWWVhcikKCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuYWxsICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChFQ08sIFllYXIpLAogICAgICAgICBlY29ZZWFyMiA9IGlmZWxzZShlY29ZZWFyID09ICJwcDIwMDEiLCAid2FybSAoMjAwMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZWNvWWVhciA9PSAicHAyMDE5IiwgIndhcm0gKDIwMTkpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY29ZZWFyID09ICJ3ZjIwMDEiLCAiY29vbCAoMjAwMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY29ZZWFyID09ICJ3ZjIwMTkiLCAiY29vbCAoMjAxOSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZWNvWWVhciA9PSAicmYyMDAxIiwgImNvbGQgKDIwMDEpIiwgImNvbGQgKDIwMTkpIikpKSkpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhcjIsIGdyb3VwID0gUE1lY29feWVhcikpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMDEpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IFllYXIpKSArCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoNDEsIDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAicGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDAxKSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKDIwMTkpIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gTWVhbiBwcm9maWxlICRcRGVsdGEkXjE0XkMgZm9yIDIwMDEgYW5kIDIwMTkgc2FtcGxlcyoqCgo+KkNhcHRpb246KiBNZWFuICRcRGVsdGEkXjE0XkMgYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDAxIGFuZCAyMDE5LiBFcnJvciBiYXJzIHNob3cgwrExIHN0YW5kYXJkIGRldmlhdGlvbi4gVmVydGljYWwgbGluZXMgc2hvdyAkXERlbHRhJF4xNF5DIG9mIHRoZSBhdG1vc3BoZXJlIGluIDIwMDEgKHNvbGlkKSBhbmQgMjAxOSAoZGFzaGVkKS4KCiMjIEluY3ViYXRpb24gJFxEZWx0YSReMTReQy1DT34yfgoKYGBge3IgaW5jLWQxNGMtcGxvdC1zZXR1cH0KIyMgMjAxOQpzcmEuMjAxOS5pbmMuZGYgPC0gYmluZF9yb3dzKHNyYS4yMDE5LmluYy5scykKIyBhZGQgbGl0dGVyIGluYyBkYXRhIGFuZCBzdW1tYXJpemUKc3JhLjIwMTkuaW5jLnN1bS5kZiA8LSBkYXRhLmZyYW1lKHJiaW5kKAogIHNyYS4yMDE5LmluY19MLnN1bVsgLCB3aGljaChuYW1lcyhzcmEuMjAxOS5pbmNfTC5zdW0pICE9ICJseXJfdG9wIildLAogIHNyYS4yMDE5LmluYy5kZiAlPiUKICAgIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgcG0gPSBmYWN0b3IoaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpLAogICAgICAgICAgICMgcmVtb3ZlIEdScmYgMTAtMjAgImEiIHBvaW50CiAgICAgICAgICAgZDE0YyA9IHJlcGxhY2UoZDE0Yywgd2hpY2goZDE0YyA8IC0zMDApLCBOQSksCiAgICAgICAgICAgWWVhciA9IGZhY3RvcihZZWFyKSkgJT4lCiAgZ3JvdXBfYnkoWWVhciwgcG0sIGVjbywgbHlyX2JvdCwgbHlyX3RvcCkgJT4lCiAgc3VtbWFyaXplKGQxNGNfbWVhbiA9IG1lYW4oZDE0YywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgZDE0Y19sID0gbWluKGQxNGMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGQxNGNfdSA9IG1heChkMTRjLCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgIHNlbGVjdCgtbHlyX3RvcCkpKQoKIyAyMDAxCnNyYS4yMDAxLmluYy5kZiA8LSBiaW5kX3Jvd3Moc3JhLjIwMDEuaW5jLmxzKQpzcmEuMjAwMS5pbmMuc3VtLmRmIDwtIGRhdGEuZnJhbWUoCiAgc3JhLjIwMDEuaW5jLmRmICU+JQogICAgbXV0YXRlKGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgcG0gPSBmYWN0b3IoaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSksCiAgICAgICAgICAgWWVhciA9IGZhY3RvcihZZWFyKSkgJT4lCiAgICBncm91cF9ieShZZWFyLCBQTWVjbywgcG0sIGVjbywgbHlyX2JvdCwgbHlyX3RvcCkgJT4lCiAgICBzdW1tYXJpemUoZDE0Y19tZWFuID0gbWVhbihkMTRjKSwKICAgICAgICAgICAgICBkMTRjX2wgPSBtaW4oZDE0YyksCiAgICAgICAgICAgICAgZDE0Y191ID0gbWF4KGQxNGMpLAogICAgICAgICAgICAgIGZtX21lYW4gPSBtZWFuKGZtKSwKICAgICAgICAgICAgICBmbV9sID0gbWluKGZtKSwKICAgICAgICAgICAgICBmbV91ID0gbWF4KGZtKSkKKQpzcmEuMjAwMS5pbmMuc3VtLmxzIDwtIHNwbGl0KHNyYS4yMDAxLmluYy5zdW0uZGYsIHNyYS4yMDAxLmluYy5zdW0uZGYkUE1lY28pCnNyYS4yMDAxLmluYy5zdW0uZGYgPC0gc3JhLjIwMDEuaW5jLnN1bS5kZlsgLCAhKG5hbWVzKHNyYS4yMDAxLmluYy5zdW0uZGYpICVpbiUgYygiZm1fbWVhbiIsICJmbV9sIiwgImZtX3UiLCAibHlyX3RvcCIsICJQTWVjbyIpKV0KYGBgCgpgYGB7ciBwbG90LWluYy1kMTRjLTIwMTl9CiMgMjAxOQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjIwMTkuaW5jLnN1bS5kZltvcmRlcihzcmEuMjAxOS5pbmMuc3VtLmRmJGx5cl9ib3QpLCBdICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aChsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDIpKSArCiAgeGxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MtQ08nWzJdKicgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuICRcRGVsdGEkXjE0XkMtQ09+Mn4gb2YgMjAxOSBidWxrIHNvaWwgaW5jdWJhdGlvbnMqKgoKPipDYXB0aW9uOiogJFxEZWx0YSReMTReQ09+Mn4gYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDE5LiBPbmUgcmVwIGZyb20gR1JyZiAxMC0yMCAodGhlIDEwLTIwIGNtIGluY3JlbWVudCBzYW1wbGUgZnJvbSB0aGUgY29sZCBncmFuaXRlIHNpdGUpIGlzIHN0cm9uZ2x5IGRlcGxldGVkIHJlbGF0aXZlIHRvIHRoZSBvdGhlciByZXA6ICRcRGVsdGEkXjE0XkMtQ09+Mn4gPSBgciB7c3JhLjIwMTkuaW5jLmRmW3NyYS4yMDE5LmluYy5kZiRQTWVjbyA9PSAiR1JyZiIgJiBzcmEuMjAxOS5pbmMuZGYkbHlyX2JvdCA9PSAyMCwgImQxNGMiXX1gLiBUaGUgaGlnaGx5IGRlcGxldGVkIHNhbXBsZSBoYXMgYmVlbiBleGNsdWRlZCBmb3IgZGlzcGxheSByZWFzb25zLgoKYGBge3IgcGxvdC1pbmMtZDE0Yy0yMDAxfQojIHBsb3QgMjAwMSBkYXRhCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMjAwMS5pbmMuc3VtLmRmICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMDEpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aCgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC03MCwgMTkwKSkgKwogIHhsYWIoZXhwcmVzc2lvbignSW5jdWJhdGlvbiAnKkRlbHRhKicnXjE0KidDLUNPJ1syXSonICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiAkXERlbHRhJF4xNF5DLUNPfjJ+IG9mIDIwMDEgYnVsayBzb2lsIGluY3ViYXRpb25zKioKCj4qQ2FwdGlvbjoqICRcRGVsdGEkXjE0XkNPfjJ+IGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAwMS4gTm90ZSB0aGF0IHNvbWUgc2l0ZXMgb25seSBoYXZlIHR3byBkZXB0aCBpbmNyZW1lbnRzLiBTaW1pbGFyIHRvIHRoZSAyMDE5IGRhdGFzZXQsIG9uZSBvZiB0aGUgR1JyZiByZXBzIGZyb20gdGhlIGRlZXBlc3QgZGVwdGggaW5jcmVtZW50IHdhcyBzdHJvbmdseSBkZXBsZXRlZDogJFxEZWx0YSReMTReQy1DT34yfiA9IGByIHtzcmEuMjAwMS5pbmMuc3VtLmRmICU+JSBmaWx0ZXIocG0gPT0gImdyYW5pdGUiLCBlY28gPT0gImNvbGQiLCBseXJfYm90ID09IDI3KSAlPiUgcHVsbCgiZDE0Y19sIiwgImQxNGNfdSIpfWAuIEJvdGggcG9pbnRzIGhhdmUgYmVlbiBleGNsdWRlZCBmb3IgZGlzcGxheSByZWFzb25zLgoKYGBge3IgcGxvdC1pbmMtZDE0Yy1hbGx9CiMgcGxvdCB0b2dldGhlcgpzcmEuaW5jLmFsbCA8LSByYmluZChzcmEuMjAwMS5pbmMuc3VtLmRmLCBzcmEuMjAxOS5pbmMuc3VtLmRmKQoKZmlnLm4gPC0gZmlnLm4gKyAxIApzcmEuaW5jLmFsbCAlPiUKICBmaWx0ZXIobHlyX2JvdCA+IDApICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKHBtLCBlY28sIFllYXIpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgWWVhciwgIikiKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4sIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciwgZ3JvdXAgPSBQTWVjb195ZWFyKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAwMSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gWWVhcikpICsKICBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYyg0MSwgMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMTkpIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC03MCwgMTkwKSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiAkXERlbHRhJF4xNF5DLUNPfjJ+IG9mIDIwMDEgYW5kIDIwMTkgYnVsayBzb2lsIGluY3ViYXRpb25zKioKCj4qQ2FwdGlvbjoqICRcRGVsdGEkXjE0XkNPfjJ+IGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAwMSBhbmQgMjAxOS4gRGlmZmVyZW50IGRlcHRoIGluY3JlbWVudHMgd2VyZSBzYW1wbGVkIGluIDIwMDEgYW5kIDIwMTkuIFBvaW50cyBhcmUgdGhlIG1lYW4gb2YgbGFib3JhdG9yeSBkdXBsaWNhdGVzOyBlcnJvciBiYXJzIGFyZSB0aGUgbWVhc3VyZWQgdmFsdWVzIG9mIGVhY2ggZHVwbGljYXRlLiBHcmFuaXRlL2NvbGQgcG9pbnQgZXhsY3VkZWQgZm9yIGRpc3BsYXkgcmVhc29ucyBhcyBpdCBpcyBzdHJvbmdseSBkZXBsZXRlZC4KCiMjIEluY3ViYXRpb24gdnMuIGJ1bGsgc29pbCAkXERlbHRhJF4xNF5DCgpgYGB7ciBpbmMtYnVsay1kMTRjLXBsb3Qtc2V0dXB9CiMgYmluZCByb3dzIG9mIGluYyBsaXN0CnNyYS4xOS5pbmMgPC0gc3JhLjIwMTkuaW5jLnN1bS5kZgpzcmEuMTkuaW5jJFR5cGUgPC0gImluYyIKCiMgMjAwMQpzcmEuMDEuaW5jIDwtIHNyYS4yMDAxLmluYy5zdW0uZGYKc3JhLjAxLmluYyRUeXBlIDwtICJpbmMiCgojIHJiaW5kIGJ1bGsgZGF0YQpzcmEuMTkuYnVsayA8LSBzcmEuMTkuc3VtW3doaWNoKHNyYS4xOS5zdW0kbHlyX2JvdCA8IDMxKSwgYygiWWVhciIsICJQTSIsICJFQ08iLCAibHlyX2JvdCIsImQxNGMiLCAiZDE0Y19sIiwgImQxNGNfdSIpXQpuYW1lcyhzcmEuMTkuYnVsaylbd2hpY2gobmFtZXMoc3JhLjE5LmJ1bGspID09ICJkMTRjIildIDwtICJkMTRjX21lYW4iCnNyYS4xOS5idWxrJFR5cGUgPC0gImJ1bGsiCnNyYS4xOS5idWxrIDwtIHNyYS4xOS5idWxrICU+JQogIG11dGF0ZShwbSA9IGZhY3RvcihpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIFBNID0gTlVMTCwKICAgICAgICAgRUNPID0gTlVMTCkKc3JhLjE5LmluYy5ibGsgPC0gcmJpbmQoZGF0YS5mcmFtZShzcmEuMTkuaW5jKSwgZGF0YS5mcmFtZShzcmEuMTkuYnVsaykpCnNhdmUoc3JhLjE5LmluYy5ibGssIGZpbGUgPSAic3JhLjE5LmluYy5ibGsuUkRhdGEiKQoKIyAyMDAxCiMgTmVlZCB0byBjYWxjdWxhdGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiByYWRpb2NhcmJvbiB2YWx1ZXMgYW5kIHN0b2NrcyBmb3IgY29tYmluZWQgaW5jIGRlcHRocyAKIyAxKSBhZGQgU09DIHN0b2NrcyB0byBkdXBsaWNhdGUgc3JhLjIwMDEubHMgb2JqCnNyYS4yMDAxLmxzMiA8LSBzcmEuMjAwMS5scwpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEubHMyKSkgewogIGl4IDwtIG1hdGNoKHNyYS4yMDAxLmxzMltbaV1dW1siSUQiXV0sIHNvYy4yMDAxLmxzW1tpXV1bWyJJRCJdXSkKICBzcmEuMjAwMS5sczJbW2ldXVsibHlyX3NvY19rZ20yIl0gPC0gc29jLjIwMDEubHNbW2ldXVtpeCwgImx5cl9zb2Nfa2dtMiJdCn0KIyAyKSB3ZWlnaHRlZCBhdmVyYWdlIGZ4CmQxZDIuMTRjLmZ4IDwtIGZ1bmN0aW9uKGRmKSB7CiAgc3VtX3NvYyA8LSBzdW0oZGZbMToyLCAibHlyX3NvY19rZ20yIl0pCiAgd3QxIDwtIGRmJGx5cl9zb2Nfa2dtMlsxXSAvIHN1bV9zb2MKICB3dDIgPC0gZGYkbHlyX3NvY19rZ20yWzJdIC8gc3VtX3NvYwogIGQxZDIgPC0gZGZbMSwgXQogIGQxZDIkSUQgPSBwYXN0ZShkZiRQTWVjb1sxXSwgZGYkcHJvX3JlcFsxXSwgZGYkbHlyX3RvcFsxXSwgZGYkbHlyX2JvdFsyXSwgc2VwID0gIl8iKQogIGQxZDIkbHlyX3NvY19rZ20yID0gc3VtKGRmJGx5cl9zb2Nfa2dtMlsxXSwgZGYkbHlyX3NvY19rZ20yWzJdKQogIGQxZDIkbHlyX2JvdCA9IGRmJGx5cl9ib3RbMl0KICBkMWQyJGZtIDwtIHN1bShkZiRmbVsxXSAqIHd0MSwgZGYkZm1bMl0gKiB3dDIpCiAgZDFkMiRkMTRjIDwtIHN1bShkZiRkMTRjWzFdICogd3QxLCBkZiRkMTRjWzJdICogd3QyKQogIHJldHVybihyYmluZChkMWQyLAogICAgICAgICAgICAgICBkZlszOm5yb3coZGYpLCBdKSkKfQojIDMpIGNhbGMuIHd0ZC4gYXZlcmFnZSBmb3IgR1JyZgpzcmEuMjAwMS5sczIkR1JyZiA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmxzMiRHUnJmLCBzcmEuMjAwMS5sczIkR1JyZiRwcm9fcmVwKSwgZnVuY3Rpb24oeCkgewogICAgZDFkMi4xNGMuZngoeCkKICB9KQopCiMgNCkgY2FsYy4gd3RkLiBhdmVyYWdlIGZvciBCU3JmCiMgICAgLSBwcm9ibGVtIGhlcmUgaXMgdGhhdCBvbmx5IG9uZSBwcm9fcmVwIGhhcyAwLTMgY20gZGF0YQojICAgIC0gc28sIG5lZWQgdG8gY2FsY3VsYXRlIHdlaWdodGVkIFNPQywgdGhlbiBjYWxjdWxhdGUgd2VpZ2h0ZWQgMTRDCiMgICAgLSBjb21wb3NpdGUgMC04ID0gMTVnIEJTcmZfMV8wLTMgKyA1IGcgZnJvbSBlYWNoIHByb19yZXAgQlNyZl8zLTgKQlNyZl9jb21wXzAxX2kgPC0gc3JhLjIwMDEubHMyJEJTcmZbd2hpY2goc3JhLjIwMDEubHMkQlNyZiRseXJfYm90IDwgOSksIF0KQlNyZl9jb21wXzAxX2kkc29jX3d0IDwtIGMoMTUgLyAzMCwgcmVwKDUgLyAzMCwgMykpCkJTcmZfY29tcF8wMV9pJHNvY193dGQgPC0gQlNyZl9jb21wXzAxX2kkbHlyX3NvY19rZ20yICogQlNyZl9jb21wXzAxX2kkc29jX3d0CgojIGNyZWF0ZSBzdW1tYXJpemVkIGxpc3QKc3JhLjIwMDEuc3VtLmxzMiAgPC0gbGFwcGx5KHNyYS4yMDAxLmxzMiwgZnVuY3Rpb24oZGYpIHsKICBkYXRhLmZyYW1lKAogICAgZGYgJT4lCiAgICAgIGZpbHRlcihseXJfYm90IDw9IDQwKSAlPiUKICAgICAgbXV0YXRlKGx5cl9ib3RfY2ggPSBhcy5jaGFyYWN0ZXIobHlyX2JvdCkpICU+JQogICAgICBzZWxlY3QoUE1lY28sIGQxNGMsIGZtLCBseXJfYm90X2NoLCBseXJfc29jX2tnbTIpICU+JQogICAgICBncm91cF9ieShQTWVjbywgbHlyX2JvdF9jaCkgJT4lCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpLCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgICAgbXV0YXRlKGx5cl9ib3QgPSBhcy5udW1lcmljKGx5cl9ib3RfY2gpKSAlPiUKICAgICAgc2VsZWN0KC1seXJfYm90X2NoKQogICkKfSkKCiMgcmVtb3ZlIEJTcmYgcm93IHcvIGx5cl9ib3QgPSAzCnNyYS4yMDAxLnN1bS5sczIkQlNyZiA8LSBzcmEuMjAwMS5zdW0ubHMyJEJTcmZbLXdoaWNoKHNyYS4yMDAxLnN1bS5sczIkQlNyZiRseXJfYm90ID09IDMpLCBdCiMgY2FsY3VsYXRlIHdlaWdodGVkIGF2ZXJhZ2UgZm9yIGQxNGMsIGZtLCBseXJfc29jX2tnbTIKc3JhLjIwMDEuc3VtLmxzMiRCU3JmW3doaWNoKHNyYS4yMDAxLnN1bS5sczIkQlNyZiRseXJfYm90ID09IDgpLCAiZDE0Y19tZWFuIl0gPC0gc3VtKEJTcmZfY29tcF8wMV9pJGQxNGMgKiAoQlNyZl9jb21wXzAxX2kkc29jX3d0ZCAvIHN1bShCU3JmX2NvbXBfMDFfaSRzb2Nfd3RkKSkpCnNyYS4yMDAxLnN1bS5sczIkQlNyZlt3aGljaChzcmEuMjAwMS5zdW0ubHMyJEJTcmYkbHlyX2JvdCA9PSA4KSwgImZtX21lYW4iXSA8LSBzdW0oQlNyZl9jb21wXzAxX2kkZm0gKiAoQlNyZl9jb21wXzAxX2kkc29jX3d0ZCAvIHN1bShCU3JmX2NvbXBfMDFfaSRzb2Nfd3RkKSkpCnNyYS4yMDAxLnN1bS5sczIkQlNyZlt3aGljaChzcmEuMjAwMS5zdW0ubHMyJEJTcmYkbHlyX2JvdCA9PSA4KSwgImx5cl9zb2Nfa2dtMl9tZWFuIl0gPC0gc3VtKEJTcmZfY29tcF8wMV9pJHNvY193dGQpCnNyYS4yMDAxLnN1bS5sczIkQlNyZlt3aGljaChzcmEuMjAwMS5zdW0ubHMyJEJTcmYkbHlyX2JvdCA9PSA4KSwgYygiZDE0Y19zZCIsICJmbV9zZCIsICJseXJfc29jX2tnbTJfc2QiKV0gPC0gTkEKCiMgY2FsY3VsYXRlIGNtdHYgc29jCnNyYS4yMDAxLnN1bS5sczIgPC0gbGFwcGx5KHNyYS4yMDAxLnN1bS5sczIsIGZ1bmN0aW9uKHgpIHsKICB4IDwtIHhbb3JkZXIoeCRseXJfYm90KSwgXQogIHgkbHlyX3NvY19jbXR2IDwtIE5BCiAgZm9yKGkgaW4gc2VxX2Fsb25nKHgkbHlyX2JvdCkpIHsKICAgICAgaWYoaSA9PSAxKSB7CiAgICAgICAgeCRseXJfc29jX2NtdHZbaV0gPC0geCRseXJfc29jX2tnbTJfbWVhbltpXQogICAgICB9IGVsc2UgewogICAgICAgIHgkbHlyX3NvY19jbXR2W2ldIDwtIHgkbHlyX3NvY19rZ20yX21lYW5baV0gKyB4JGx5cl9zb2NfY210dltpLTFdIAogICAgICB9CiAgfQogIHJldHVybih4KQp9KQoKIyBtYWtlIGRmCnNyYS4wMS5zdW0gPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MoCiAgbGFwcGx5KHNyYS4yMDAxLnN1bS5sczIsIGZ1bmN0aW9uKGRmKSB7CiAgICBkZiAlPiUKICAgICAgbXV0YXRlKGVjbyA9IGZhY3RvcihpZmVsc2UoZ3JlcGwoInBwIiwgZGYkUE1lY28pLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgid2YiLCBkZiRQTWVjbyksICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICBwbSA9IGlmZWxzZShncmVwbCgiQU4iLCBkZiRQTWVjbyksICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkJTIiwgZGYkUE1lY28pLCAiYmFzYWx0IiwgImdyYW5pdGUiKSksCiAgICAgICAgICAgICBkMTRjX3UgPSBkMTRjX21lYW4gKyBkMTRjX3NkLAogICAgICAgICAgICAgZDE0Y19sID0gZDE0Y19tZWFuIC0gZDE0Y19zZCwKICAgICAgICAgICAgIFllYXIgPSAyMDAxLAogICAgICAgICAgICAgVHlwZSA9ICJidWxrIikgJT4lCiAgICAgIHNlbGVjdChuYW1lcyhzcmEuMDEuaW5jKSkgJT4lCiAgICAgIGFycmFuZ2UobHlyX2JvdCkKICB9KQopKQojIGJpbmQgd2l0aCBpbmMKc3JhLjAxLmluYy5ibGsgPC0gcmJpbmQoZGF0YS5mcmFtZShzcmEuMDEuaW5jKSwgc3JhLjAxLnN1bSkKc2F2ZShzcmEuMDEuaW5jLmJsaywgZmlsZSA9ICJzcmEuMDEuaW5jLmJsay5SRGF0YSIpCmBgYAoKYGBge3IgcGxvdC1pbmMtYmxrLTIwMTl9CiMgcGxvdCAyMDE5CmZpZy5uIDwtIGZpZy5uICsgMQojIHAgPC0Kc3JhLjE5LmluYy5ibGsgJT4lCiAgbXV0YXRlKEVDT3R5cGUgPSBwYXN0ZTAoZWNvLCAiICgiLCBUeXBlLCAiKSIpKSAlPiUKICBhcnJhbmdlKGx5cl9ib3QpICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IEVDT3R5cGUsIGxpbmV0eXBlID0gVHlwZSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgZ2VvbV9wYXRoKCkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtICh0eXBlKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKGJ1bGspIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoYnVsaykiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIChidWxrKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoaW5jKSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoaW5jKSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoaW5jKSIgPSAyKSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgZ2dzYXZlKCJzcmEuYnVsa0luYy4xOS5wZGYiLCBwLCBkZXZpY2UgPSBjYWlyb19wZGYsIHdpZHRoID0gOS41LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiAkXERlbHRhJF4xNF5DIG9mIDIwMTkgYnVsayBzb2lsIGluY3ViYXRpb25zIGFuZCBjb3JyZXNwb25kaW5nIGJ1bGsgc29pbCoqCgo+KkNhcHRpb246KiAkXERlbHRhJF4xNF5DIG9mIGJ1bGsgc29pbCBhbmQgcmVzcGlyZWQgQ09+Mn4gYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDE5LiBFcnJvciBiYXJzIHNob3cgb25lIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgYnVsayBzb2lsLCBwb2ludHMgc2hvdyBtZWFuIG9mIHRocmVlIHJlcGxpY2F0ZSBwcm9maWxlcyBmb3IgYnVsayBzb2lscyBhbmQgc2luZ2xlIG9ic2VydmF0aW9ucyBmb3IgcmVzcGlyZWQgQ09+Mn4uIAoKYGBge3IgcGxvdC1pbmMtYmxrLTIwMDF9CiMgcGxvdCAyMDAxCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMDEuaW5jLmJsayAlPiUKICBtdXRhdGUoRUNPdHlwZSA9IHBhc3RlMChlY28sICIgKCIsIFR5cGUsICIpIikpICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IEVDT3R5cGUsIGxpbmV0eXBlID0gVHlwZSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMDEpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgZ2VvbV9wYXRoKCkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtICh0eXBlKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKGJ1bGspIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoYnVsaykiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIChidWxrKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoaW5jKSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoaW5jKSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoaW5jKSIgPSAyKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0xMDAsIDIwMCkpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gJFxEZWx0YSReMTReQyBvZiAyMDAxIGJ1bGsgc29pbCBpbmN1YmF0aW9ucyBhbmQgY29ycmVzcG9uZGluZyBidWxrIHNvaWwqKgoKPipDYXB0aW9uOiogJFxEZWx0YSReMTReQyBvZiBidWxrIHNvaWwgYW5kIHJlc3BpcmVkIENPfjJ+IGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAwMS4gUG9pbnRzIHNob3cgbWVhbiBvZiB0aHJlZSByZXBsaWNhdGUgcHJvZmlsZXMgZm9yIGJ1bGsgc29pbHMgYW5kIG1lYW4gb2YgbGFib3JhdG9yeSBkdXBsaWNhdGVzIGZvciByZXNwaXJlZCBDT34yfi4gVGhlIGluY3ViYXRlZCBzb2lsIHNhbXBsZXMgYXJlIGEgY29tcG9zaXRlIG1hZGUgYnkgaG9tb2dlbml6aW5nIHN1YnNhbXBsZXMgZnJvbSBlYWNoIG9mIHRoZSB0aHJlZSByZXBsaWNhdGUgcHJvZmlsZSBzYW1wbGVzIGJ5IGRlcHRoLiBFcnJvciBiYXJzIHNob3cgb25lIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgYnVsayBzb2lsIGFuZCB0aGUgbWVhc3VyZWQgdmFsdWVzIGZyb20gbGFib3JhdG9yeSBkdXBsaWNhdGVzIG9mIHRoZSBpbmN1YmF0ZWQgY29tcG9zaXRlIHNhbXBsZXMuCgpgYGB7ciBwcmVwLWluYy1ieS1idWxrLTE0Yy1wbG90fQojIGZpcnN0IG1lcmdlIG1lYW4gMTRDIGRhdGEgZnJvbSAyMDE5IHNhbXBsZXMgd2l0aCBjb21wb3NpdGUgaW5jdWJhdGlvbiBkYXRhCm5tcy5pbmMuYmxrIDwtIGMoInBtIiwgImVjbyIsICJseXJfYm90IiwgIlllYXIiKQpzcmEuMTkuaW5jLmJsazIgPC0gbGVmdF9qb2luKHNyYS4xOS5idWxrICU+JSBtdXRhdGUoLiwgWWVhciA9IGFzLmZhY3RvcihZZWFyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JhLjIwMTkuaW5jLnN1bS5kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IG5tcy5pbmMuYmxrLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeCA9IGMoIi5idWxrIiwgIi5pbmMiKSkKIyAyMDAxCnNyYS4wMS5pbmMuYmxrMiA8LSBsZWZ0X2pvaW4oc3JhLjAxLnN1bSAlPiUgbXV0YXRlKC4sIFllYXIgPSBhcy5mYWN0b3IoWWVhcikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYS4wMS5pbmMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBubXMuaW5jLmJsaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWZmaXggPSBjKCIuYnVsayIsICIuaW5jIikpCnNyYS4wMS5pbmMuYmxrMiRQTWVjbyA8LSBwYXN0ZTAoc3JhLjAxLmluYy5ibGsyJHBtLCBzcmEuMDEuaW5jLmJsazIkZWNvKQojIGFkZCBkZXB0aCBmYWN0b3IKc3JhLjAxLmluYy5ibGsyIDwtIHVuc3BsaXQoCiAgbGFwcGx5KHNwbGl0KHNyYS4wMS5pbmMuYmxrMiwgc3JhLjAxLmluYy5ibGsyJFBNZWNvKSwgZnVuY3Rpb24oeCkgewogIHgkZGVwdGggPC0gc2VxKDEsIG5yb3coeCkpCiAgcmV0dXJuKHgpIAogIH0pLCAKc3JhLjAxLmluYy5ibGsyJFBNZWNvKQpzcmEuMDEuaW5jLmJsazIgPC0gc3JhLjAxLmluYy5ibGsyW3doaWNoKHNyYS4wMS5pbmMuYmxrMiRseXJfYm90IDwgMzUpLCBdCnNyYS4wMS5pbmMuYmxrMiRkZXB0aCA8LSBmYWN0b3Ioc3JhLjAxLmluYy5ibGsyJGRlcHRoKQoKIyByZWdyZXNzIGJ1bGsgdnMuIGluYwptaW4uaW5jLmJsay4xOSA8LSBtaW4oc3JhLjE5LmluYy5ibGsyJGQxNGNfbC5pbmMsCiAgICAgICAgICAgICAgICAgICAgICBzcmEuMTkuaW5jLmJsazIkZDE0Y19sLmJ1bGspICMgZXhjbHVkZSBoaWdobHkgbmVnYXRpdmUgaW5jdWJhdGlvbiBzYW1wbGUgZnJvbSBHUndmCm1heC5pbmMuYmxrLjE5IDwtIG1heChzcmEuMTkuaW5jLmJsazIkZDE0Y19sLmluYywKICAgICAgICAgICAgICAgICAgICAgIHNyYS4xOS5pbmMuYmxrMiRkMTRjX2wuYnVsaykKCiMgV2hhdCBpcyB0aGUgaWRlYWwgZ3JvdXBpbmcvZXhwZWN0ZWQgcmVsYXRpb25zaGlwPwpgYGAKCmBgYHtyIHBsb3QtaW5jLWJ5LWJ1bGstMTRjfQojIyBsb29rIGF0IGNvbWJpbmF0b3JpYWwgZGF0YXNldAojIHNyYS5hbGwuZGYuZnggPC0gZnVuY3Rpb24obHMsIHllYXIpIHsKIyAgIGNiaW5kKGJpbmRfcm93cyhsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSBkZlsgLCBjKCJQTWVjbyIsICJseXJfYm90IiwgImQxNGMiKV0pKSwKIyAgICAgICAgIHllYXIgPSB5ZWFyKQojIH0KIyBzcmEuYWxsLmRmIDwtIGlubmVyX2pvaW4oCiMgICByYmluZChzcmEuYWxsLmRmLmZ4KHNyYS4yMDAxLmxzLCAyMDAxKSwKIyAgICAgICAgIHNyYS5hbGwuZGYuZngoc3JhLjIwMTkubHMsIDIwMTkpKSwKIyAgIHJiaW5kKHNyYS5hbGwuZGYuZngoc3JhLjIwMDEuaW5jLmxzLCAyMDAxKSwKIyAgICAgICAgIHNyYS5hbGwuZGYuZngoc3JhLjIwMTkuaW5jLmxzLCAyMDE5KSksCiMgICBieSA9IGMoIlBNZWNvIiwgImx5cl9ib3QiLCAieWVhciIpLAojICAgc3VmZml4ID0gYygiX2J1bGsiLCAiX2luYyIpKQojIHNyYS5hbGwuZGYgPC0gc3JhLmFsbC5kZiAlPiUKIyAgIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjbywgMSwgMiksCiMgICAgICAgICAgRUNPID0gc3Vic3RyKFBNZWNvLCAzLCA0KSkKIyAKIyBzcmEuYWxsLmRmICU+JQojICAgZmlsdGVyKGQxNGNfaW5jID4gLTEzMCkgJT4lCiMgICBnZ3Bsb3QoLiwgYWVzKGQxNGNfYnVsaywgZDE0Y19pbmMsIGNvbG9yID0gUE0pKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKIyAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgYWVzKGZpbGwgPSBQTSkpICsKIyAgIGdlb21fcG9pbnQoKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSwKIyAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIikpICsKIyAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSwKIyAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIikpICsKIyAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xMzAsIDIwMCksIHlsaW0gPSBjKC0xMzAsIDIwMCkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbignQnVsayBzb2lsICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeWxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgdGhlbWVfYncoKSArCiMgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQojICAgCiMgc3VtbWFyeShsbShkMTRjX2luYyB+IGQxNGNfYnVsayAqIFBNLCBzcmEuYWxsLmRmW3NyYS5hbGwuZGYkZDE0Y19pbmMgPiAtMTMwLCBdKSkKCiMgam9pbiBhbGwgZGF0YSBhcyBtZWFucyBhbmQgc2RzCnNyYS5hbGwuc3VtLmRmIDwtIGxlZnRfam9pbigKICBiaW5kX3Jvd3Moc3JhLjIwMDEuc3VtLmxzMikgJT4lCiAgICBzZWxlY3QoUE1lY28sIGx5cl9ib3QsIGQxNGNfbWVhbiwgZDE0Y19zZCkgJT4lCiAgICBtdXRhdGUoWWVhciA9IDIwMDEpICU+JQogICAgYmluZF9yb3dzKC4sIAogICAgICAgICAgICAgIGJpbmRfcm93cyhsYXBwbHkoc3JhLjIwMTkubHMsIGZ1bmN0aW9uKGRmKSB7CiAgICAgICAgICAgICAgICBkZiAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGx5cl9ib3QgPCAzMSkgJT4lCiAgICAgICAgICAgICAgICAgIHNlbGVjdChQTWVjbywgbHlyX2JvdCwgZDE0YykgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KFBNZWNvLCBseXJfYm90KSAlPiUKICAgICAgICAgICAgICAgICAgc3VtbWFyaXplKGFjcm9zcyhkMTRjLCBsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkpICU+JQogICAgICAgICAgICAgICAgICBtdXRhdGUoWWVhciA9IDIwMTkpCiAgICAgICAgICAgICAgICB9KSkKICAgICAgICAgICAgKSwKICBiaW5kX3Jvd3MobGFwcGx5KHNyYS4yMDAxLmluYy5scywgZnVuY3Rpb24oZGYpIHsKICAgICAgICAgICAgICBkZiAlPiUKICAgICAgICAgICAgICAgIHNlbGVjdChQTWVjbywgbHlyX2JvdCwgZDE0YykgJT4lCiAgICAgICAgICAgICAgICBncm91cF9ieShQTWVjbywgbHlyX2JvdCkgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpemUoYWNyb3NzKGQxNGMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoWWVhciA9IDIwMDEpIAogICAgICAgICAgICAgIH0pKSAlPiUKICBiaW5kX3Jvd3MoLiwgCiAgICAgICAgICAgIGJpbmRfcm93cyhsYXBwbHkoc3JhLjIwMTkuaW5jLmxzLCBmdW5jdGlvbihkZikgewogICAgICAgICAgICAgIGRmICU+JQogICAgICAgICAgICAgICAgc2VsZWN0KFBNZWNvLCBseXJfYm90LCBkMTRjKSAlPiUKICAgICAgICAgICAgICAgIGdyb3VwX2J5KFBNZWNvLCBseXJfYm90KSAlPiUKICAgICAgICAgICAgICAgIHN1bW1hcml6ZShhY3Jvc3MoZDE0YywgbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCkpKSAlPiUKICAgICAgICAgICAgICAgIG11dGF0ZShZZWFyID0gMjAxOSkKICAgICAgICAgICAgICB9KSkKICAgICAgICAgICAgKSwgCiAgYnkgPSBjKCJQTWVjbyIsICJseXJfYm90IiwgIlllYXIiKSwKICBzdWZmaXggPSBjKCIuYnVsayIsICIuaW5jIikpICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cmluZyhQTWVjbywgMSwgMiksCiAgICAgICAgIGVjbyA9IHN1YnN0cmluZyhQTWVjbywgMywgNCkpCgojIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBvZiBtZWFucwpzdW1tYXJ5KGxtKGQxNGNfbWVhbi5pbmMgfiBkMTRjX21lYW4uYnVsayAqIFBNLCBzcmEuYWxsLnN1bS5kZltzcmEuYWxsLnN1bS5kZiRkMTRjX21lYW4uaW5jID4gLTIwMCwgXSkpCgojIGxhcHBseShzcGxpdChzcmEuYWxsLnN1bS5kZiwgc3JhLmFsbC5zdW0uZGYkZWNvKSwgZnVuY3Rpb24oZGYpIHsKIyAgIHN1bW1hcnkobG0oZDE0Y19tZWFuLmluYyB+IGQxNGNfbWVhbi5idWxrICogUE0sIGRmKSkKIyB9KQoKIyAjIERlbWluZyByZWdyZXNzaW9uIChhY2NvdW50cyBmb3IgZXJyb3IgaW4geCBhbmQgeSB0ZXJtcykKIyBzcmEuZGVtIDwtIGxhcHBseShzcGxpdChzcmEuYWxsLnN1bS5kZiwgc3JhLmFsbC5zdW0uZGYkUE0pLCBmdW5jdGlvbihkZikgewojICAgZGVtaW5nKGQxNGNfbWVhbi5pbmMgfiBkMTRjX21lYW4uYnVsaywKIyAgICAgICAgZGF0YSA9IGRmLCB4c3RkID0gZDE0Y19zZC5pbmMsIHlzdGQgPSBkMTRjX3NkLmJ1bGspCiMgfSkKCiMgYWxsIGRlcHRocyBhbmQgeWVhcnMgdG9nZXRoZXIsIGJ5IFBNCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMTkuaW5jLmJsazIgICU+JQogIGJpbmRfcm93cyguLCBzcmEuMDEuaW5jLmJsazJbICwgd2hpY2gobmFtZXMoc3JhLjE5LmluYy5ibGsyKSAlaW4lIG5hbWVzKHNyYS4wMS5pbmMuYmxrMikpXSkgJT4lCiAgbXV0YXRlKGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgWWVhciwgIikiKSkgJT4lCiAgZmlsdGVyKGQxNGNfbWVhbi5pbmMgPiAtMjAwKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbi5idWxrLCBkMTRjX21lYW4uaW5jLCBjb2xvciA9IHBtKSkgKwogICMgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogICMgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciksIHNpemUgPSAzKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiB4LCBzZSA9IEZBTFNFKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbC5idWxrLCAKICAgICAgICB4bWF4ID0gZDE0Y191LmJ1bGssCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gZDE0Y19sLmluYywgCiAgICAgICAgeW1heCA9IGQxNGNfdS5pbmMsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgd2lkdGggPSAxLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDE5KSIgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDAxKSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3KSkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xMDAsIDIwMCksIHlsaW0gPSBjKC0xMDAsIDIwMCkpICsKICB4bGFiKGV4cHJlc3Npb24oJ0J1bGsgc29pbCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKGV4cHJlc3Npb24oJ0luY3ViYXRpb24gJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgIyBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGRlcHRoKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojICMgMjAwMQojIHNyYS4wMS5pbmMuYmxrMiAlPiUKIyAgIGZpbHRlcihkMTRjX21lYW4uYnVsayA+IC0xMDAgJiBkMTRjX21lYW4uaW5jID4gLTEwMCkgJT4lCiMgICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbi5idWxrLCBkMTRjX21lYW4uaW5jLCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgZ3JvdXAgPSBwbSkpICsKIyAgICMgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICAjIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIHNlID0gRkFMU0UpICsKIyAgIGdlb21fZXJyb3JiYXJoKAojICAgICBhZXMoeG1pbiA9IGQxNGNfbC5idWxrLCAKIyAgICAgICAgIHhtYXggPSBkMTRjX3UuYnVsaywKIyAgICAgICAgIGNvbG9yID0gcG0pLCAKIyAgICAgaGVpZ2h0ID0gMS41KSArCiMgICBnZW9tX2Vycm9yYmFyKAojICAgICBhZXMoeW1pbiA9IGQxNGNfbC5pbmMsIAojICAgICAgICAgeW1heCA9IGQxNGNfdS5pbmMsCiMgICAgICAgICBjb2xvciA9IHBtKSwgCiMgICAgIHdpZHRoID0gMS41KSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKIyAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xMDAsIDIwMCksIHlsaW0gPSBjKC0xMDAsIDIwMCkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbignQnVsayBzb2lsICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeWxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhkZXB0aCkpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyAKIyAjIDIwMTkKIyBmaWcubiA8LSBmaWcubiArIDEKIyBzcmEuMTkuaW5jLmJsazIgJT4lCiMgICBtdXRhdGUoZGVwdGggPSBmYWN0b3IobHlyX2JvdCkpICU+JQojICAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4uYnVsaywgZDE0Y19tZWFuLmluYywgY29sb3IgPSBwbSwgc2hhcGUgPSBlY28sIGdyb3VwID0gcG0pKSArCiMgICAjIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwojICAgIyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKIyAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKIyAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9wb2ludChzaXplID0gMykgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiB4LCBzZSA9IEZBTFNFKSArCiMgICBnZW9tX2Vycm9yYmFyaCgKIyAgICAgYWVzKHhtaW4gPSBkMTRjX2wuYnVsaywgCiMgICAgICAgICB4bWF4ID0gZDE0Y191LmJ1bGssCiMgICAgICAgICBjb2xvciA9IHBtKSwgCiMgICAgIGhlaWdodCA9IDEuNSkgKwojICAgZ2VvbV9lcnJvcmJhcigKIyAgICAgYWVzKHltaW4gPSBkMTRjX2wuaW5jLCAKIyAgICAgICAgIHltYXggPSBkMTRjX3UuaW5jLAojICAgICAgICAgY29sb3IgPSBwbSksIAojICAgICB3aWR0aCA9IDEuNSkgKwojICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKIyAgIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDIpKSArCiMgICBjb29yZF9maXhlZCh4bGltID0gYygtMTAwLCAyMDApLCB5bGltID0gYygtMTAwLCAyMDApKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0J1bGsgc29pbCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignSW5jdWJhdGlvbiAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZGVwdGgpKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBSZWdyZXNzaW9uIG9mIDIwMTkgYnVsayBzb2lsIGluY3ViYXRpb25zIGFuZCBjb3JyZXNwb25kaW5nIGJ1bGsgc29pbCAkXERlbHRhJF4xNF5DKioKCj4qQ2FwdGlvbjoqIFJlZ3Jlc3Npb25zIG9mICRcRGVsdGEkXjE0XkMgb2YgYnVsayBzb2lsIGFuZCByZXNwaXJlZCBDT34yfiBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMTkuIEVycm9yIGJhcnMgc2hvdyBvbmUgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBidWxrIHNvaWwsIHBvaW50cyBzaG93IG1lYW4gb2YgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGZvciBidWxrIHNvaWxzIGFuZCBzaW5nbGUgb2JzZXJ2YXRpb25zIGZvciByZXNwaXJlZCBDT34yfi4KCiMjIFRpbWUgc2VyaWVzOiAkXERlbHRhJF4xNF5DIGJ5IGRlcHRoIChhcyBtZWFzdXJlZCkKYGBge3IgcGxvdC10aW1lc2VyaWVzLW1lYXMtZGVwdGhzfQojIGNvbWJpbmUgJzAxLCAnMDksICcxOSBkYXRhCnNyYS4wMS4wOS4xOS5yYXcgPC0gcmJpbmQoYmluZF9yb3dzKHNyYS4yMDAxLnN1bS5scyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKHNyYS4yMDE5LnN1bS5scykpCnNyYS4yMDA5LmxzIDwtIHNwbGl0KHJhczE4Lmx5ciwgcmFzMTgubHlyJFBNZWNvKQpzcmEuMjAwOS5kZiA8LSBiaW5kX3Jvd3Moc3JhLjIwMDkubHMpCmNvbG5hbWVzKHNyYS4yMDA5LmRmKVt3aGljaChjb2xuYW1lcyhzcmEuMjAwOS5kZikgPT0gImx5cl8xNGMiKV0gPC0gImQxNGMiCnNyYS4yMDA5LmRmIDwtIHNyYS4yMDA5LmRmWyAsIHdoaWNoKG5hbWVzKHNyYS4yMDA5LmRmKSAlaW4lIG5hbWVzKHNyYS4wMS4wOS4xOS5yYXcpKV0Kc3JhLjIwMDkuZGYgPC0gY2JpbmQoc3JhLjIwMDkuZGYsIAogICAgICAgICAgICAgICAgICAgICBmbSA9IE5BLAogICAgICAgICAgICAgICAgICAgICBkMTRjX3NkID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIGZtX3NkID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIGQxNGNfdSA9IE5BLAogICAgICAgICAgICAgICAgICAgICBkMTRjX2wgPSBOQSkKc3JhLjAxLjA5LjE5LnJhdyA8LSByYmluZChzcmEuMDEuMDkuMTkucmF3LCBzcmEuMjAwOS5kZikKc3JhLjAxLjA5LjE5LnJhdyRZZWFyIDwtIGZhY3RvcihjKHJlcCgyMDAxLCBucm93KGJpbmRfcm93cyhzcmEuMjAwMS5zdW0ubHMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoMjAxOSwgbnJvdyhiaW5kX3Jvd3Moc3JhLjIwMTkuc3VtLmxzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKDIwMDksIG5yb3coc3JhLjIwMDkuZGYpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMjAwMSIsICIyMDA5IiwgIjIwMTkiKSkKCiMgcGxvdAojIHcvIHJpYmJvbnMKIyBzcmEuMDEuMDkuMTkucmF3ICU+JQojICAgbXV0YXRlKFBNZWNvX3llYXIgPSBwYXN0ZTAoUE1lY28sIFllYXIpLAojICAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKIyAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAojICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKIyAgICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKIyAgICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKIyAgICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAojICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpICU+JQojICAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBncm91cCA9IFBNZWNvX3llYXIpKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3JpYmJvbihhZXMoeG1pbiA9IGQxNGNfbCwgeG1heCA9IGQxNGNfdSwgZmlsbCA9IHBtLCBhbHBoYSA9IFllYXIsIGdyb3VwID0gUE1lY29feWVhciksCiMgICAgICAgICAgICAgICBjb2xvciA9IE5BLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiMgICBnZW9tX3BvaW50KGFlcyhmaWxsID0gcG0sIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBhbHBoYSA9IFllYXIpLCBzaXplID0gMikgKwojICAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBlY28pLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArCiMgICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gWWVhciwgY29sb3IgPSBwbSksIHNpemUgPSAwLjcpICsKIyAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKIyAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKIyAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDIyLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDIxLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDI0KSkgKwojICAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoIjIwMDEiID0gLjYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAwLjQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAxOSIgPSAwLjIpKSArCiMgICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwojICAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIHlsYWIoIkRlcHRoIChjbSkiKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGxpdHRlcgpzcmEuMjAxOS5pbmMuTC5kZiA8LSBkYXRhLmZyYW1lKAogIHNyYS4yMDE5LmluY19MLmRmICU+JQogICAgZ3JvdXBfYnkoWWVhciwgUE0sIGVjbywgbHlyX2JvdCwgUE1lY28pICU+JQogICAgc3VtbWFyaXplKGFjcm9zcyguY29scyA9IGQxNGMsIAogICAgICAgICAgICAgICAgICAgICAuZm5zID0gbGlzdChtZWFuID0gbWVhbiwgbWluID0gbWluLCBtYXggPSBtYXgpKSkgJT4lCiAgICByZW5hbWUoeWVhciA9IFllYXIsIGQxNGMgPSBkMTRjX21lYW4pICU+JQogICAgbXV0YXRlKGVjbyA9IGZhY3RvcihpZmVsc2UoZWNvID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY28gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkpCiMgZm9yIHBsb3R0aW5nIGJlbG93CnNyYS4yMDE5LmluYy5MLmRmMiA8LSBzcmEuMjAxOS5pbmMuTC5kZiAlPiUKICByZW5hbWUoZDE0Y19sID0gZDE0Y19taW4sCiAgICAgICAgIGQxNGNfdSA9IGQxNGNfbWF4KSAlPiUKICBtdXRhdGUoUE1lY29feWVhciA9IHBhc3RlMChQTWVjbywgeWVhcikpCgojIHdpdGggZXJyb3IgYmFycywgYWxsIGRlcHRocwpzcmEuMDEuMDkuMTkucmF3ICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBncm91cCA9IFBNZWNvX3llYXIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KGFlcyhmaWxsID0gcG0sIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBhbHBoYSA9IFllYXIpLCBzaXplID0gMy41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gc3JhLjIwMTkuaW5jLkwuZGYyLCAKICAgICAgICAgICAgIGFlcyhkMTRjLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbyksIHNoYXBlID0gOCwgc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBZZWFyLCBjb2xvciA9IHBtKSwgc2l6ZSA9IDAuNykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtLAogICAgICAgIGFscGhhID0gWWVhciksCiAgICBoZWlnaHQgPSAxLjUpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKICBzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDA5IiA9IDAuNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAxOSIgPSAwLjMpKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoIjIwMDEiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9IDMpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMganVzdCB0b3Bzb2lsLCB3LyBlcnJvciBiYXJzCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMDEuMDkuMTkucmF3IDwtIHNyYS4wMS4wOS4xOS5yYXdbb3JkZXIoc3JhLjAxLjA5LjE5LnJhdyRseXJfdG9wKSwgXQpzcmEuMDEuMDkuMTkucmF3ICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBncm91cCA9IFBNZWNvX3llYXIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KGFlcyhmaWxsID0gcG0sIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBhbHBoYSA9IFllYXIpLCBzaXplID0gMykgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBZZWFyLCBjb2xvciA9IHBtKSwgc2l6ZSA9IDAuNykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtLAogICAgICAgIGFscGhhID0gWWVhciksCiAgICBoZWlnaHQgPSAxLjUpICsKICBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYyg0MSwgMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTYwLCAxOTApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0iID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKICBzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDA5IiA9IDAuNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAxOSIgPSAwLjMpKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoIjIwMDEiID0gInNvbGlkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAxOSIgPSAiZG90dGVkIikpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gVGltZSBzZXJpZXMgb2YgJFxEZWx0YSReMTReQyBieSBkZXB0aCwgYXMgbWVhc3VyZWQqKgoKPipDYXB0aW9uOiogUG9pbnRzIHNob3cgbWVhbiBvZiB0aHJlZSBwcm9maWxlIHJlcGxpY2F0ZXMgZm9yIDIwMDEsIDIwMDksIGFuZCAyMDE5IHNhbXBsZXMuIEVycm9yIGJhcnMgc2hvdyDCsSAxIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbWVhbiAob25seSBhIHNpbmdsZSBwcm9maWxlIHdhcyBhbmFseXplZCBpbiAyMDA5KS4gU3RhcnMgc2hvdyBsaXR0ZXIgaW5jdWJhdGlvbiAkXERlbHRhJF4xNF5DLUNPfjJ+IGZvciAyMDE5IHNhbXBsZXMgYXMgYSBwb2ludCBvZiByZWZlcmVuY2UuCgojIyBTcGxpbmUgZml0dGluZwoKU29pbHMgY29sbGVjdGVkIGluIGJvdGggdGhlIDIwMDEgYW5kIDIwMDkgc2FtcGxpbmcgY2FtcGFpZ25zIHdlcmUgc2FtcGxlZCBieSBob3Jpem9uLCBidXQgdGhlIGRlcHRoIGludGVydmFscyBkaWZmZXJlZCBiZXR3ZWVuIHRoZSB0d28gc2FtcGxpbmcgeWVhcnMuIEluIDIwMDksIGZ1bGwgcHJvZmlsZXMgd2VyZSBleGNhdmF0ZWQgZm9yIGVhY2ggc2l0ZSwgYXMgb3Bwb3NlZCB0byB0aGUgc2hvcnRlciBwcm9maWxlcyBjb2xsZWN0ZWQgaW4gMjAwMSBmcm9tIHRoZSBHUiBhbmQgQU4gc2l0ZXMuIFJhZGlvY2FyYm9uIHdhcyBtZWFzdXJlZCBvbiBhbGwgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGF0IGVhY2ggc2l0ZSBmb3IgdGhlIDIwMDEgc2FtcGxlcywgYnV0IG9ubHkgZm9yIG9uZSBvZiB0aGUgcmVwbGljYXRlIHByb2ZpbGVzIGF0IGVhY2ggc2l0ZSBpbiAyMDA5LCBlLmcuIEFOcHAgcmVwMiwgZXRjLgoKSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgcmFkaW9jYXJib24gcHJvZmlsZXMgYmV0d2VlbiAyMDAxLCAyMDA5LCBhbmQgMjAxOSB3ZSBmaXJzdCBpbnRlcnBvbGF0ZWQgYm90aCByYWRpb2NhcmJvbiBhbmQgY2FyYm9uIHN0b2NrIGRhdGEgYXQgMSBjbSBpbnRlcnZhbHMgZm9yIGVhY2ggc2l0ZSBpbiB0aGUgZGF0YXNldHMgZnJvbSBlYWNoIHllYXIuIFRoZSBjYXJib24tc3RvY2std2VpZ2h0ZWQgcmFkaW9jYXJib24gdmFsdWVzIGZvciBhbnkgZ2l2ZW4gdGFyZ2V0IGRlcHRoIGludGVydmFsIGNhbiB0aGVuIGJlIGNhbGN1bGF0ZWQgYXMgYSBzaW1wbGUgc3VtIG9mIHRoZSBwcm9kdWN0IG9mIHRoZSBjYXJib24gd2VpZ2h0IG9mIGVhY2ggMSBjbSBpbmNyZW1lbnQgKHJlbGF0aXZlIHRvIHRoZSB0b3RhbCBjYXJib24gc3RvY2sgb2YgdGhlIHRhcmdldCBkZXB0aCBpbnRlcnZhbCkgYW5kIGl0cyByYWRpb2NhcmJvbiB2YWx1ZS4gQSBtb25vdG9uaWMgY3ViaWMgc3BsaW5lIGZpdCB3YXMgdXNlZCBmb3IgdGhlIGNhcmJvbiBzdG9jayBpbnRlcnBvbGF0aW9uIChXZW5kdCBhbmQgSGF1c2VyIDIwMTMpLCBhbmQgYSBtYXNzLXByZXNlcnZpbmcgc3BsaW5lIHdhcyB1c2VkIHRvIGZpdCB0aGUgcmFkaW9jYXJib24gZGF0YSAoQmlzaG9wLCBULkYuQS4sIE1jQnJhdG5leSwgQS5CLiwgTGFzbGV0dCwgRy5NLiwgKDE5OTkpIE1vZGVsbGluZyBzb2lsIGF0dHJpYnV0ZSBkZXB0aCBmdW5jdGlvbnMgd2l0aCBlcXVhbC1hcmVhIHF1YWRyYXRpYyBzbW9vdGhpbmcgc3BsaW5lcy4gR2VvZGVybWEsIDkxKDEtMik6IDI3LTQ1KS4KCmBgYHtyIGNuLWNsZWFuLCBpbmNsdWRlID0gRkFMU0V9CmVsbV9yZXN1bHRzX2RmIDwtIGJpbmRfcm93cyh1bmxpc3QoZWxtX3Jlc3VsdHNfbHMsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKIyBTcGxpdCBJRHMKUE1lY29fcmVwX2RlcHRoIDwtIGJpbmRfcm93cygKICBsYXBwbHkoc3Ryc3BsaXQoZWxtX3Jlc3VsdHNfZGYkSUQsICJfIiksIGZ1bmN0aW9uKHgpIHsgCiAgICBkZiA8LSAgZGF0YS5mcmFtZShQTWVjbyA9IHhbMl0sCiAgICAgICAgICAgICAgICAgICAgICBwcm9fcmVwID0geFszXSwKICAgICAgICAgICAgICAgICAgICAgIGRlcHRoID0geFs0XSkKICAgIGRmJFBNIDwtIHN1YnN0cihkZiRQTWVjbywgMSwgMikKICAgIGRmJEVDTyA8LSBzdWJzdHIoZGYkUE1lY28sIDMsIDQpCiAgICByZXR1cm4oZGYpCiAgfSkKKQplbG1fcmVzdWx0c19kZiA8LSBjYmluZChlbG1fcmVzdWx0c19kZiwgUE1lY29fcmVwX2RlcHRoKQpgYGAKCmBgYHtyIHNvYy0yMDAxLCBpbmNsdWRlID0gRkFMU0V9CiMgbWVyZ2Ugc29jLjIwMDEubHMgYW5kIHNyYS4yMDAxLmxzIHRvIGFkZCBTT0MgZGF0YQpzcmEuMjAwMS5scyA8LSBtYXBwbHkobWVyZ2UsIHNyYS4yMDAxLmxzLCBzb2MuMjAwMS5scywgU0lNUExJRlkgPSBGQUxTRSkKCiMgY2FsY3VsYXRlIGN1bXVsYXRpdmUgc3RvY2tzCnNyYS4yMDAxLmxzIDwtIGxhcHBseShzcmEuMjAwMS5scywgZnVuY3Rpb24oZGYpIHsKICBscyA8LSBzcGxpdChkZiwgZGYkcHJvX25hbWUpCiAgbHMgPC0gbGFwcGx5KGxzLCBmdW5jdGlvbih4KSB7CiAgICB4IDwtIHhbb3JkZXIoeCRseXJfYm90KSwgXSAjIG1ha2Ugc3VyZSB0byBvcmRlciBkYXRhCiAgICB4JGx5cl9zb2NfY210diA8LSBOQQogICAgZm9yKGkgaW4gc2VxX2Fsb25nKHgkbHlyX2JvdCkpIHsKICAgICAgaWYoaSA9PSAxKSB7CiAgICAgICAgeCRseXJfc29jX2NtdHZbaV0gPC0geCRseXJfc29jX2tnbTJbaV0KICAgICAgfSBlbHNlIHsKICAgICAgICB4JGx5cl9zb2NfY210dltpXSA8LSB4JGx5cl9zb2Nfa2dtMltpXSArIHgkbHlyX3NvY19jbXR2W2ktMV0gCiAgICAgIH0KICAgIH0KICAgIHJldHVybih4KQogIH0pCiAgcmV0dXJuKHVuc3BsaXQobHMsIGRmJHByb19uYW1lKSkKfSkKYGBgCgpgYGB7ciBzcGxpbmUtZm0sIGluY2x1ZGUgPSBGQUxTRX0KIyMjIHNwbGluZSBmaXQgZm9yIGZtCiMjIGJ1bGsgKHNwbGl0IGJ5IHBybyByZXApCiMgMjAwMQpzcmEuMjAwMS5mbS5zcCA8LSBsYXBwbHkoc3JhLjIwMDEubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIGRlcHRocyh4KSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgICB4Lm1wcyA8LSBtcHNwbGluZSh4LCB2YXIubmFtZSA9ICJmbSIpCiAgICB4Lm1wcyR2YXIuMWNtIDwtIHgubXBzJHZhci4xY21bMTptYXgoeCRseXJfYm90KV0KICAgIHJldHVybih4Lm1wcykKICB9KQp9KQojIDIwMDkKc3JhLjIwMDkuZm0uc3AgPC0gbGFwcGx5KHNyYS4yMDA5LmxzLCBmdW5jdGlvbih4KSB7CiAgZGVwdGhzKHgpIDwtIHByb19uYW1lIH4gbHlyX3RvcCArIGx5cl9ib3QKICB4Lm1wcyA8LSBtcHNwbGluZSh4LCB2YXIubmFtZSA9ICJseXJfZnJhY3Rpb25fbW9kZXJuIikKICB4Lm1wcyR2YXIuMWNtIDwtIHgubXBzJHZhci4xY21bMTptYXgoeCRseXJfYm90KV0KICByZXR1cm4oeC5tcHMpCn0pCiMgMjAxOQpzcmEuMjAxOS5mbS5zcCA8LSBsYXBwbHkoc3JhLjIwMTkubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIGRlcHRocyh4KSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgICB4Lm1wcyA8LSBtcHNwbGluZSh4LCB2YXIubmFtZSA9ICJmbSIpCiAgICB4Lm1wcyR2YXIuMWNtIDwtIHgubXBzJHZhci4xY21bMTptYXgoeCRseXJfYm90KV0KICAgIHJldHVybih4Lm1wcykKICB9KQp9KQoKIyMgaW5jCiMgbmVlZCBtaW4gYW5kIG1heCB2YWx1ZXMgZm9yIHNwbGluZSBmaXRzCiMgMjAwMQpzcmEuMjAwMS5pbmMuZm0uc3AgPC0gbGFwcGx5KHNyYS4yMDAxLmluYy5zdW0ubHMsIGZ1bmN0aW9uKGRmKSB7CiAgICBkZXB0aHMoZGYpIDwtIFBNZWNvIH4gbHlyX3RvcCArIGx5cl9ib3QKICAgIG1lYW4ubXBzIDwtIG1wc3BsaW5lKGRmLCB2YXIubmFtZSA9ICJmbV9tZWFuIikKICAgIG1pbi5tcHMgPC0gbXBzcGxpbmUoZGYsIHZhci5uYW1lID0gImZtX2wiKQogICAgbWF4Lm1wcyA8LSBtcHNwbGluZShkZiwgdmFyLm5hbWUgPSAiZm1fdSIpCiAgICByZXR1cm4obGlzdChtZWFuLnZhci4xY20gPSBtZWFuLm1wcyR2YXIuMWNtWzE6bWF4KGRmJGx5cl9ib3QpXSwKICAgICAgICAgICAgICAgIG1pbi52YXIuMWNtID0gbWluLm1wcyR2YXIuMWNtWzE6bWF4KGRmJGx5cl9ib3QpXSwKICAgICAgICAgICAgICAgIG1heC52YXIuMWNtID0gbWF4Lm1wcyR2YXIuMWNtWzE6bWF4KGRmJGx5cl9ib3QpXSkpCiAgfSkKYGBgCgpgYGB7ciBzcGxpbmUtYmQtc29jLTE5LCBpbmNsdWRlID0gRkFMU0V9CiMgTmVlZCBTT0Mgc3RvY2sgZGF0YSBmb3IgMjAxOSBzYW1wbGVzOiB1c2UgQkQgZnJvbSAyMDA5IHNhbXBsZXMgCiMgc3BsaW5lIGZpdCBmb3IgYnVsayBkZW5zaXR5CnNyYS4yMDA5LmJkLnNwIDwtIGxhcHBseShzcmEuMjAwOS5scywgZnVuY3Rpb24oeCkgewogIGRlcHRocyh4KSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgeC5tcHMgPC0gbXBzcGxpbmUoeCwgdmFyLm5hbWUgPSAibHlyX2JkX3NhbXAiKQogIHgubXBzJHZhci4xY20gPC0geC5tcHMkdmFyLjFjbVsxOjEwMF0KICByZXR1cm4oeC5tcHMpCn0pCnNyYS4yMDA5LmJkLnNwIDwtIGxhcHBseShzcmEuMjAwOS5iZC5zcCwgZnVuY3Rpb24obHMpIHsKICBkZiA8LSBkYXRhLmZyYW1lKGxzWyJ2YXIuMWNtIl0pCiAgaXggPC0gd2hpY2goaXMubmEoZGYkdmFyLjFjbSkpCiAgZGYkdmFyLjFjbVtpeF0gPC0gZGYkdmFyLjFjbVtpeFsxXS0xXQogIHJldHVybihkZikKfSkKCiMgY2FsY3VsYXRlIG1lYW4gb2YgMWNtIEJEIHByZWRpY3Rpb25zIGZvciBlYWNoIGRlcHRoIGluY3JlbWVudApiZF9wcmVkIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkuYmQuc3ApLCBmdW5jdGlvbihpKSB7CiAgbHMgPC0gc3BsaXQoc3JhLjIwMTkubHNbW2ldXSwgc3JhLjIwMTkubHNbW2ldXVsicHJvX3JlcCJdKSAjIHNwbGl0IGVhY2ggcmVwbGljYXRlIHByb2ZpbGUKICBscyA8LSBsYXBwbHkoc2VxX2Fsb25nKGxzKSwgZnVuY3Rpb24oZGYpIHsKICAgIGQgPC0gbHNbW2RmXV1bWyJseXJfYm90Il1dICMgZGVwdGggaW50ZXJ2YWxzCiAgICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpICMgdmVjdG9yIGZvciBhdmVyYWdpbmcgMSBjbSBiZCBwcmVkCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgY1tbal1dIDwtIG1lYW4oc3JhLjIwMDkuYmQuc3BbW2ldXVsxOmRbal0sICJ2YXIuMWNtIl0pICMgMS0xMAogICAgICB9IGVsc2UgewogICAgICAgIGNbW2pdXSA8LSBtZWFuKHNyYS4yMDA5LmJkLnNwW1tpXV1bKGRbai0xXSsxKTpkW2pdLCAidmFyLjFjbSJdKSAjIDEwIGNtIGluY3JlbWVudHMKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChjKSkKICAgIH0pCiAgcmV0dXJuKHVuc3BsaXQobHMsIHNyYS4yMDE5LmxzW1tpXV1bInByb19yZXAiXSkpCn0pCgojIG1lcmdlIHByZWRpY3RlZCBiZCB2YWx1ZXMgd2l0aCBzcmEuMjAxOS5scwpubXMgPC0gbmFtZXMoc3JhLjIwMTkubHMpCnNyYS4yMDE5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMTkubHMpLCBmdW5jdGlvbihkZikgewogIGNiaW5kKHNyYS4yMDE5LmxzW1tkZl1dLCBiZCA9IGJkX3ByZWRbW2RmXV0pCn0pCm5hbWVzKHNyYS4yMDE5LmxzKSA8LSBubXMKCiMgYWRkIGMgY29uYwpzcmEuMjAxOS5scyA8LSBsYXBwbHkoc3JhLjIwMTkubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGYkZGVwdGggPC0gcGFzdGUwKGRmJGx5cl90b3AsICItIiwgZGYkbHlyX2JvdCkKICBkZiA8LSBtZXJnZShkZiwgZWxtX3Jlc3VsdHNfZGZbICwgYygiUE1lY28iLCAicHJvX3JlcCIsICJkZXB0aCIsICJDIiwgIk4iKV0sIGJ5ID0gYygiUE1lY28iLCAiZGVwdGgiLCAicHJvX3JlcCIpKQogIHJldHVybihkZikKfSkKCiMgY2FsY3VsYXRlIHN0b2NrcyAgCnNyYS4yMDE5LmxzIDwtIGxhcHBseShzcmEuMjAxOS5scywgZnVuY3Rpb24oZGYpIHsKICBkZiRseXJfc29jIDwtIGRmJGJkICogZGYkQyAjIHVuaXRzIHdvcmsgb3V0IHRvIGtnX20yIAogIHJldHVybihkZikKfSkKIyBjYWxjdWxhdGUgY210diBzdG9ja3MKc3JhLjIwMTkubHMgPC0gbGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgewogIGxzIDwtIHNwbGl0KGRmLCBkZiRwcm9fbmFtZSkKICBscyA8LSBsYXBwbHkobHMsIGZ1bmN0aW9uKHgpIHsKICAgIHgkbHlyX3NvY19jbXR2IDwtIE5BCiAgICBmb3IoaSBpbiBzZXFfYWxvbmcoeCRseXJfYm90KSkgewogICAgICBpZihpID09IDEpIHsKICAgICAgICB4JGx5cl9zb2NfY210dltpXSA8LSB4JGx5cl9zb2NbaV0KICAgICAgfSBlbHNlIHsKICAgICAgICB4JGx5cl9zb2NfY210dltpXSA8LSB4JGx5cl9zb2NbaV0gKyB4JGx5cl9zb2NfY210dltpLTFdIAogICAgICB9CiAgICB9CiAgICByZXR1cm4oeCkKICB9KQogIHJldHVybih1bnNwbGl0KGxzLCBkZiRwcm9fbmFtZSkpCn0pCnNhdmUoc3JhLjIwMTkubHMsIGZpbGUgPSAic3JhLjIwMTkubHMuUkRhdGEiKQpgYGAKCmBgYHtyIHNwbGluZS1zb2MsIGluY2x1ZGUgPSBGQUxTRX0KIyBzcGxpbmUgZml0IGZvciBjYXJib24gc3RvY2tzIChmb3IgY2FsYyB3ZWlnaHRlZCBhdmVyYWdlcykKZGVwdGguc3BsaW5lIDwtIGZ1bmN0aW9uKHgpIHsKICBzcCA8LSBzcGxpbmUoeCwgbWV0aG9kID0gImh5bWFuIikgIyBmaXQgbW9ub3RvbmljIGN1YmljIHNwbGluZQogIHNwLnNzIDwtIHNtb290aC5zcGxpbmUoc3ApICMgY29udmVydCB0byBjbGFzcyAic3BsaW5lIiB3aXRoIHNtb290aC5zcGxpbmUgZnhuCiAgc3RkIDwtIHNlcSgwLCAxMDApICMgaW4gY20gKGxpbmVhciBiZXlvbmQgbGFzdCBtZWFzdXJlZCBkZXB0aCkKICBzcCA8LSBwcmVkaWN0KHNwLnNzLCBzdGQpIAogIGRmIDwtIGRhdGEuZnJhbWUoc3ApCiAgY29sbmFtZXMoZGYpIDwtIGMoImx5cl9ib3QiLCJseXJfc29jIikKICBmb3IoaSBpbiBzZXFfYWxvbmcoZGYkbHlyX2JvdCkpIHsKICAgIGlmKGkgPT0gMSkgewogICAgICBkZiRseXJfc29jW2ldIDwtIGRmJGx5cl9zb2NbaV0KICAgIH0gZWxzZSB7CiAgICAgIGRmJGx5cl9zb2NbaV0gPC0gZGYkbHlyX3NvY1tpICsgMV0gLSBkZiRseXJfc29jW2ldCiAgICB9CiAgfQogIGRmIDwtIGRmWy0xLF0KICByZXR1cm4oZGZbLWxlbmd0aChkZiRseXJfc29jKSwgXSkKfQoKIyMgYWRkICgwLCAwKSBwb2ludCBmb3IgKGx5cl9ib3QsIGx5cl9jbXR2X3N0b2NrKQojIDIwMDEKc3JhLjIwMDEuc3AubHMgPC0gbGFwcGx5KHNyYS4yMDAxLmxzLCBmdW5jdGlvbihkZikgewogIGxzIDwtIGxhcHBseShzcGxpdChkZiwgZGYkcHJvX25hbWUpLCBmdW5jdGlvbih4KSB7CiAgICB0MCA8LSBkYXRhLmZyYW1lKG1hdHJpeChucm93ID0gMSwgbmNvbCA9IG5jb2woeCkpKQogICAgeHkgPC0gYyh3aGljaChuYW1lcyh4KSA9PSAibHlyX2JvdCIpLCB3aGljaChuYW1lcyh4KSA9PSAibHlyX3NvY19jbXR2IikpCiAgICB0MFsgLCB4eV0gPC0gMAogICAgbmFtZXModDApIDwtIG5hbWVzKHgpCiAgICB0MCRwcm9fbmFtZSA8LSB1bmlxdWUoeCRwcm9fbmFtZSkKICAgIHJldHVybihyYmluZCh0MCwgeCkpCiAgfSkKICByZXR1cm4oYmluZF9yb3dzKGxzKSkKfSkKc3JhLjIwMDEuc3AubHMuYXZnIDwtIGxhcHBseShzcmEuMjAwMS5zdW0ubHMyLCBmdW5jdGlvbihkZikgewogIHh5IDwtIGRmWyAsIGMoImx5cl9ib3QiLCAibHlyX3NvY19jbXR2IildCiAgdDAgPC0gZGF0YS5mcmFtZShseXJfYm90ID0gMCwgbHlyX3NvY19jbXR2ID0gMCkKICByZXR1cm4ocmJpbmQoeHkpKQp9KQojIDIwMDkKc3JhLjIwMDkuc3AubHMgPC0gbGFwcGx5KHNyYS4yMDA5LmxzLCBmdW5jdGlvbihkZikgewogIHQwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAxLCBuY29sID0gbmNvbChkZikpKQogIHh5IDwtIGMod2hpY2gobmFtZXMoZGYpID09ICJseXJfYm90IiksIHdoaWNoKG5hbWVzKGRmKSA9PSAibHlyX3NvY19jbXR2IikpCiAgdDBbICwgeHldIDwtIDAKICBuYW1lcyh0MCkgPC0gbmFtZXMoZGYpCiAgbmV3IDwtIHJiaW5kKHQwLCBkZikKICByZXR1cm4obmV3KQp9KQojIDIwMTkKc3JhLjIwMTkuc3AubHMgPC0gbGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgewogIGxzIDwtIGxhcHBseShzcGxpdChkZiwgZGYkcHJvX25hbWUpLCBmdW5jdGlvbih4KSB7CiAgICB0MCA8LSBkYXRhLmZyYW1lKG1hdHJpeChucm93ID0gMSwgbmNvbCA9IG5jb2woeCkpKQogICAgeHkgPC0gYyh3aGljaChuYW1lcyh4KSA9PSAibHlyX2JvdCIpLCB3aGljaChuYW1lcyh4KSA9PSAibHlyX3NvY19jbXR2IikpCiAgICB0MFsgLCB4eV0gPC0gMAogICAgbmFtZXModDApIDwtIG5hbWVzKHgpCiAgICB0MCRwcm9fbmFtZSA8LSB1bmlxdWUoeCRwcm9fbmFtZSkKICAgIHJldHVybihyYmluZCh0MCwgeCkpCiAgfSkKICByZXR1cm4oYmluZF9yb3dzKGxzKSkKfSkKCiMjIHJ1biBzcGxpbmUKIyAyMDAxCnNyYS4yMDAxLm9jLnNwIDwtIGxhcHBseShzcmEuMjAwMS5zcC5scywgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJHByb19uYW1lKSwgZnVuY3Rpb24oeCkgewogICAgZGVwdGguc3BsaW5lKHhbLCBjKCJseXJfYm90IiwgImx5cl9zb2NfY210diIpXSkKICB9KQp9KQpzcmEuMjAwMS5vYy5zcC5hdmcgPC0gbGFwcGx5KHNyYS4yMDAxLnNwLmxzLmF2ZywgZnVuY3Rpb24oZGYpIHsKICBkZXB0aC5zcGxpbmUoZGYpCn0pCiMgMjAwOQpzcmEuMjAwOS5vYy5zcCA8LSBsYXBwbHkoc3JhLjIwMDkuc3AubHMsIGZ1bmN0aW9uKHgpIHsKICBkZXB0aC5zcGxpbmUoeFssIGMoImx5cl9ib3QiLCAibHlyX3NvY19jbXR2IildKQp9KQojIDIwMTkKc3JhLjIwMTkub2Muc3AgPC0gbGFwcGx5KHNyYS4yMDE5LnNwLmxzLCBmdW5jdGlvbihkZikgewogIGxhcHBseShzcGxpdChkZiwgZGYkcHJvX25hbWUpLCBmdW5jdGlvbih4KSB7CiAgICBkZXB0aC5zcGxpbmUoeFssIGMoImx5cl9ib3QiLCAibHlyX3NvY19jbXR2IildKQogIH0pCn0pCmBgYAoKYGBge3IgY3d0LWQxNGMtMDEsIGluY2x1ZGUgPSBGQUxTRX0KIyMgY2FsY3VsYXRlIHN0b2NrIHdlaWdodHMKIyMgMjAwMSBkZXB0aHMKIyBvcmRlciAnMDEgZGF0YQpzcmEuMjAwMS5zdW0ubHMgPC0gbGFwcGx5KHNyYS4yMDAxLnN1bS5scywgZnVuY3Rpb24oZGYpIGRmW29yZGVyKGRmJGx5cl9ib3QpLCBdKQojIDIwMDkKY3d0LjAxLjA5IDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkub2Muc3ApLCBmdW5jdGlvbihpKSB7CiAgZCA8LSBzcmEuMjAwMS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0gIyBtYXAgb250byAnMDEgZGVwdGhzCiAgYyA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgaWYoaiA9PSAxKSB7CiAgICAgIGNbW2pdXSA8LSBzcmEuMjAwOS5vYy5zcFtbaV1dWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgfSBlbHNlIHsKICAgICAgY1tbal1dIDwtIHNyYS4yMDA5Lm9jLnNwW1tpXV1bKGRbai0xXSsxKTpkW2pdLCAibHlyX3NvYyJdIAogICAgfQogIH0KICByZXR1cm4odW5saXN0KGxhcHBseShjLCBmdW5jdGlvbih4KSB4L3N1bSh4KSkpKSAjIHJldHVybiB3ZWlnaHRzCn0pCm5hbWVzKGN3dC4wMS4wOSkgPC0gbmFtZXMoc3JhLjIwMDkub2Muc3ApCiMgMjAxOSAoc2Vjb25kIGxpc3QgbGV2ZWwgZnJvbSBwcm9maWxlIHJlcHMpCmN3dC4wMS4xOSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5Lm9jLnNwKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzcmEuMjAxOS5vYy5zcFtbaV1dLCBmdW5jdGlvbihkZikgewogICAgZCA8LSBzcmEuMjAwMS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0gIyBtYXAgb250byAnMDEgZGVwdGhzCiAgICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgY1tbal1dIDwtIGRmWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgICB9IGVsc2UgewogICAgICAgIGNbW2pdXSA8LSBkZlsoZFtqLTFdKzEpOmRbal0sICJseXJfc29jIl0gCiAgICAgIH0KICAgIH0KICAgIHJldHVybih1bmxpc3QobGFwcGx5KGMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkpICAjIHJldHVybiB3ZWlnaHRzCiAgfSkKfSkKbmFtZXMoY3d0LjAxLjE5KSA8LSBuYW1lcyhzcmEuMjAxOS5vYy5zcCkKCgojIyBjYWxjdWxhdGUgZm1fd3RzCiMjICcwMSBkZXB0aHMKIyAyMDE5CmZtLnd0LjAxLjE5IDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxLjE5KSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxLjE5W1tpXV0pLCBmdW5jdGlvbihqKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4wMS4xOVtbaV1dW1tqXV0pCiAgICBkZiRmbSA8LSBzcmEuMjAxOS5mbS5zcFtbaV1dW1tqXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4wMS4xOVtbaV1dW1tqXV0pXQogICAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCiAgfSkKfSkgCm5hbWVzKGZtLnd0LjAxLjE5KSA8LSBuYW1lcyhjd3QuMDEuMTkpCiMgMjAwOQpmbS53dC4wMS4wOSA8LSBsYXBwbHkoc2VxX2Fsb25nKGN3dC4wMS4wOSksIGZ1bmN0aW9uKGkpIHsKICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4wMS4wOVtbaV1dKQogIGRmJGZtIDwtIHNyYS4yMDA5LmZtLnNwW1tpXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4wMS4wOVtbaV1dKV0KICBkZiRmbV93dCA8LSBkZiRmbSAqIGRmJGN3dAogIHJldHVybihkZikKfSkKbmFtZXMoZm0ud3QuMDEuMDkpIDwtIG5hbWVzKGN3dC4wMS4wOSkKCgojIyBjYWxjdWxhdGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiBmbSBmb3IgZWFjaCBpbnRlcnZhbAojIyAnMDEgZGVwdGhzCiMgMjAwOQpzcmEuMDEuMDkubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMjAwMS5zdW0ubHMpLCBmdW5jdGlvbihpKSB7CiAgZCA8LSBzcmEuMjAwMS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICBmIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgZm9yKGogaW4gc2VxX2Fsb25nKGQpKSB7CiAgICBpZihqID09IDEpIHsKICAgICAgZltbal1dIDwtIHN1bShmbS53dC4wMS4wOVtbaV1dWzE6ZFtqXSwgImZtX3d0Il0pCiAgICB9IGVsc2UgewogICAgICBmW1tqXV0gPC0gc3VtKGZtLnd0LjAxLjA5W1tpXV1bKGRbai0xXSsxKTpkW2pdLCAiZm1fd3QiXSkKICAgIH0KICB9CiAgcmV0dXJuKGNiaW5kKHNyYS4yMDAxLnN1bS5sc1tbaV1dLCBmbV8wOSA9IHVubGlzdChmKSkpCn0pCm5hbWVzKHNyYS4wMS4wOS5scykgPC0gbmFtZXMoZm0ud3QuMDEuMDkpCiMgMjAxOQpzcmEuMDEuMTkubHMgPC0gZm0ud3QuMDEuMTkgIyBpbml0aWFsaXplIGxpc3Qgd2l0aCBmbSB3dCBzdHJ1Y3R1cmUKc3JhLjAxLjE5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDEuc3VtLmxzKSwgZnVuY3Rpb24oaSkgewogIHNyYS4wMS4xOS5sc1tbaV1dIDwtIGxhcHBseShzZXFfYWxvbmcoZm0ud3QuMDEuMTlbW2ldXSksIGZ1bmN0aW9uKHgpIHsKICAgIGQgPC0gc3JhLjIwMDEuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgICBmIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgZltbal1dIDwtIHN1bShmbS53dC4wMS4xOVtbaV1dW1t4XV1bMTpkW2pdLCAiZm1fd3QiXSkKICAgICAgfSBlbHNlIHsKICAgICAgICBmW1tqXV0gPC0gc3VtKGZtLnd0LjAxLjE5W1tpXV1bW3hdXVsoZFtqLTFdKzEpOmRbal0sICJmbV93dCJdKQogICAgICB9CiAgICB9CiAgICByZXR1cm4odW5saXN0KGYpKSAKICB9KQogIGZtIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjAxLjE5LmxzW1tpXV1bWzFdXSksIGZ1bmN0aW9uKHopIHsKICAgIGRhdGEuZnJhbWUoZm1fMTlfbWVhbiA9IG1lYW4oc2FwcGx5KHNyYS4wMS4xOS5sc1tbaV1dLCAiWyIsIHopLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICBmbV8xOV9zZCA9IHNkKHNhcHBseShzcmEuMDEuMTkubHNbW2ldXSwgIlsiLCB6KSwgbmEucm0gPSBUUlVFKSkKICAgIH0pCiAgZm0gPC0gYmluZF9yb3dzKGZtKQogIHJldHVybihmbSkKfSkKc3JhLjAxLjA5LjE5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjAxLjA5LmxzKSwgZnVuY3Rpb24oaSkgewogIGRhdGEuZnJhbWUoc3JhLjAxLjA5LmxzW1tpXV0sIHNyYS4wMS4xOS5sc1tbaV1dKQp9KQpuYW1lcyhzcmEuMDEuMDkuMTkubHMpIDwtIG5hbWVzKHNyYS4wMS4wOS5scykKCiMjIGNyZWF0ZSB0aWR5IGNvbWJpbmVkICcwMSwgJzA5LCAnMTkgZGF0YSBmcmFtZQpubXMgPC0gYygiUE0iLCAiRUNPIiwgIlBNZWNvIiwgImx5cl90b3AiLCAibHlyX2JvdCIsICJmbSIsICJmbV9zZCIpCnNyYS4wMS4wOS4xOS5kZiA8LSBiaW5kX3Jvd3Moc3JhLjAxLjA5LjE5LmxzKQpzcmEuMDEuMDkuMTkgPC0gc3JhLjAxLjA5LjE5LmRmWywgbm1zXQpzcmEuMDEuMDkuMTkgPC0gcmJpbmQoY2JpbmQoc3JhLjAxLjA5LjE5LCBZZWFyID0gYXMuY2hhcmFjdGVyKDIwMDEpKSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoc3JhLjAxLjA5LjE5Wywgbm1zWzE6NV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbSA9IHNyYS4wMS4wOS4xOS5kZiRmbV8wOSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm1fc2QgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9IGFzLmNoYXJhY3RlcigyMDA5KSksCiAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHNyYS4wMS4wOS4xOVssIG5tc1sxOjVdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm0gPSBzcmEuMDEuMDkuMTkuZGYkZm1fMTlfbWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm1fc2QgPSBzcmEuMDEuMDkuMTkuZGYkZm1fMTlfc2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXIgPSBhcy5jaGFyYWN0ZXIoMjAxOSkpKQoKIyBjYWxjIGQxNGMgZnJvbSBmbQpzcmEuMDEuMDkuMTkkZDE0YyA8LSBjYWxjXzE0YyhzcmEuMDEuMDkuMTkkZm0sIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHNyYS4wMS4wOS4xOSRZZWFyKSkpCnNyYS4wMS4wOS4xOSRkMTRjX3NkIDwtIGFicyhzcmEuMDEuMDkuMTkkZDE0YyAtIGNhbGNfMTRjKHNyYS4wMS4wOS4xOSRmbSArIHNyYS4wMS4wOS4xOSRmbV9zZCwgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3JhLjAxLjA5LjE5JFllYXIpKSkpCmBgYAoKYGBge3IgY3d0LWQxNGMtMTksIGluY2x1ZGUgPSBGQUxTRX0KIyMgY2FsY3VsYXRlIHN0b2NrIHdlaWdodHMKIyMgMjAxOSBkZXB0aHMKIyAyMDAxCmN3dC4xOS4wMSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDAxLm9jLnNwKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzcmEuMjAwMS5vYy5zcFtbaV1dLCBmdW5jdGlvbihkZikgewogICAgZCA8LSBzcmEuMjAxOS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICAgIGMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICAgIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgICBpZihqID09IDEpIHsKICAgICAgICBjW1tqXV0gPC0gZGZbMTpkW2pdLCAibHlyX3NvYyJdCiAgICAgIH0gZWxzZSB7CiAgICAgICAgY1tbal1dIDwtIGRmWyhkW2otMV0rMSk6ZFtqXSwgImx5cl9zb2MiXSAKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChsYXBwbHkoYywgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKSkKICB9KQp9KQpuYW1lcyhjd3QuMTkuMDEpIDwtIG5hbWVzKHNyYS4yMDAxLm9jLnNwKQojIDIwMDEgbWVhbgpjd3QuMTkuMDEuYXZnIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDEub2Muc3AuYXZnKSwgZnVuY3Rpb24oaSkgewogICAgZCA8LSBzcmEuMjAxOS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICAgIGMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICAgIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgICBpZihqID09IDEpIHsKICAgICAgICBjW1tqXV0gPC0gc3JhLjIwMDEub2Muc3AuYXZnW1tpXV1bMTpkW2pdLCAibHlyX3NvYyJdCiAgICAgIH0gZWxzZSB7CiAgICAgICAgY1tbal1dIDwtIHNyYS4yMDAxLm9jLnNwLmF2Z1tbaV1dWyhkW2otMV0rMSk6ZFtqXSwgImx5cl9zb2MiXSAKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChsYXBwbHkoYywgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKSkKfSkKbmFtZXMoY3d0LjE5LjAxLmF2ZykgPC0gbmFtZXMoc3JhLjIwMDEub2Muc3ApCgojIDIwMDkKY3d0LjE5LjA5IDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkub2Muc3ApLCBmdW5jdGlvbihpKSB7CiAgZCA8LSBzcmEuMjAxOS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgZm9yKGogaW4gc2VxX2Fsb25nKGQpKSB7CiAgICBpZihqID09IDEpIHsKICAgICAgY1tbal1dIDwtIHNyYS4yMDA5Lm9jLnNwW1tpXV1bMTpkW2pdLCAibHlyX3NvYyJdCiAgICB9IGVsc2UgewogICAgICBjW1tqXV0gPC0gc3JhLjIwMDkub2Muc3BbW2ldXVsoZFtqLTFdKzEpOmRbal0sICJseXJfc29jIl0gCiAgICB9CiAgfQogIHJldHVybih1bmxpc3QobGFwcGx5KGMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkpCn0pCm5hbWVzKGN3dC4xOS4wOSkgPC0gbmFtZXMoc3JhLjIwMDkub2Muc3ApCgojIyBjYWxjdWxhdGUgZm1fd3RzCiMjICcxOSBkZXB0aHMKIyMgYnVsawojIDIwMDEKZm0ud3QuMTkuMDEgPC0gbGFwcGx5KHNlcV9hbG9uZyhjd3QuMTkuMDEpLCBmdW5jdGlvbihpKSB7CiAgbGFwcGx5KHNlcV9hbG9uZyhjd3QuMTkuMDFbW2ldXSksIGZ1bmN0aW9uKGopIHsKICAgIGRmIDwtIGRhdGEuZnJhbWUoY3d0ID0gY3d0LjE5LjAxW1tpXV1bW2pdXSkKICAgIGRmJGZtIDwtIHNyYS4yMDAxLmZtLnNwW1tpXV1bW2pdXVtbInZhci4xY20iXV1bMTpsZW5ndGgoY3d0LjE5LjAxW1tpXV1bW2pdXSldCiAgICAjIGxpbmVhciBleHRyYXBvbGF0aW9uIGZvciBmaWxsaW5nIDIwLTMwY20gZm0gZGF0YQogICAgZm1fMV8zMCA8LSBkZiRmbVsxOjMwXSAjIDAtMzBjbSBmbQogICAgaWYobGVuZ3RoKHdoaWNoKGlzLm5hKGZtXzFfMzApKSkgPiAwKSB7CiAgICAgaXggPC0gd2hpY2goaXMubmEoZm1fMV8zMCkpCiAgICAgaXgubWluIDwtIG1pbihpeCkgIyBmaXJzdCBpcy5uYShmbSkKICAgICBtIDwtIGZtXzFfMzBbaXgubWluLTFdLWZtXzFfMzBbaXgubWluLTJdICMgc2xvcGUgYXQgbGFzdCB0d28gbWVhc3VyZW1lbnQgcG9pbnRzCiAgICAgZm9yKGkgaW4gaXgubWluOjMwKSB7CiAgICAgIGZtXzFfMzBbaV0gPC0gZm1fMV8zMFtpIC0gMV0gKyBtIAogICAgIH0KICAgICBkZiRmbVsxOjMwXSA8LSBmbV8xXzMwIAogICAgfQogICAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCiAgfSkKfSkKbmFtZXMoZm0ud3QuMTkuMDEpIDwtIG5hbWVzKGN3dC4xOS4wMSkKIyAnMDEgaW5jCmZtLnd0LjE5LjAxLmluYyA8LSBsYXBwbHkoc2VxX2Fsb25nKGN3dC4xOS4wMS5hdmcpLCBmdW5jdGlvbihqKSB7CiAgbGFwcGx5KHNyYS4yMDAxLmluYy5mbS5zcFtbal1dLCBmdW5jdGlvbihmbSkgewogICAgZGYgPC0gZGF0YS5mcmFtZShjd3QgPSBjd3QuMTkuMDEuYXZnW1tqXV1bMTozMF0pCiAgICAjIGxpbmVhciBleHRyYXBvbGF0aW9uIGZvciBmaWxsaW5nIDIwLTMwY20gZm0gZGF0YQogICAgaWYgKGxlbmd0aChmbSkgPj0gMzApIHsKICAgICAgZm1fMV8zMCA8LSBmbVsxOjMwXSAjIDAtMzBjbSBmbQogICAgfSBlbHNlIHsKICAgICAgZm1fMV8zMCA8LSByZXAoTkEsIDMwKQogICAgICBmbV8xXzMwWzE6bGVuZ3RoKGZtKV0gPC0gZm0KICAgICAgIyBmaXJzdCBpcy5uYShmbSkKICAgICAgaXgubWluIDwtIG1pbih3aGljaChpcy5uYShmbV8xXzMwKSkpCiAgICAgICMgc2xvcGUgYXQgbGFzdCB0d28gbWVhc3VyZW1lbnQgcG9pbnRzCiAgICAgIG0gPC0gZm1fMV8zMFtpeC5taW4gLSAxXSAtIGZtXzFfMzBbaXgubWluIC0gMl0KICAgICAgZm9yKHggaW4gaXgubWluOjMwKSB7CiAgICAgICAgZm1fMV8zMFt4XSA8LSBmbV8xXzMwW3ggLSAxXSArIG0KICAgICAgfQogICAgfQogICAgZGYkZm1bMTozMF0gPC0gZm1fMV8zMCAKICAgIGRmJGZtX3d0IDwtIGRmJGZtICogZGYkY3d0CiAgICByZXR1cm4oZGYpCiAgfSkKfSkKbmFtZXMoZm0ud3QuMTkuMDEuaW5jKSA8LSBuYW1lcyhjd3QuMTkuMDEuYXZnKQoKIyAyMDA5CmZtLnd0LjE5LjA5IDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5LjA5KSwgZnVuY3Rpb24oaSkgewogIGRmIDwtIGRhdGEuZnJhbWUoY3d0ID0gY3d0LjE5LjA5W1tpXV0pCiAgZGYkZm0gPC0gc3JhLjIwMDkuZm0uc3BbW2ldXVtbInZhci4xY20iXV1bMTpsZW5ndGgoY3d0LjE5LjA5W1tpXV0pXQogIGRmJGZtX3d0IDwtIGRmJGZtICogZGYkY3d0CiAgcmV0dXJuKGRmKQp9KQpuYW1lcyhmbS53dC4xOS4wOSkgPC0gbmFtZXMoY3d0LjE5LjA5KQoKIyMgY2FsY3VsYXRlIHdlaWdodGVkIGF2ZXJhZ2Ugb2YgZm0gZm9yIGVhY2ggaW50ZXJ2YWwKIyMgJzE5IGRlcHRocwojIDIwMDEKIyBjYWxjdWxhdGUgd2VpZ2h0ZWQgc3BsaW5lIHZhbHVlcyBmb3IgZWFjaCBwcm9maWxlIHJlcApzcmEuMTkuMDEucmVwLmxzIDwtIGZtLnd0LjE5LjAxCnNyYS4xOS4wMS5yZXAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMjAxOS5zdW0ubHMpLCBmdW5jdGlvbihpKSB7CiAgc3JhLjE5LjAxLnJlcC5sc1tbaV1dIDwtIGxhcHBseShzZXFfYWxvbmcoZm0ud3QuMTkuMDFbW2ldXSksIGZ1bmN0aW9uKHgpIHsKICAgIGQgPC0gc3JhLjIwMTkuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgICBmIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgZltbal1dIDwtIHN1bShmbS53dC4xOS4wMVtbaV1dW1t4XV1bMTpkW2pdLCAiZm1fd3QiXSkKICAgICAgfSBlbHNlIHsKICAgICAgICBmW1tqXV0gPC0gc3VtKGZtLnd0LjE5LjAxW1tpXV1bW3hdXVsoZFtqLTFdKzEpOmRbal0sICJmbV93dCJdKQogICAgICB9CiAgICB9CiAgICByZXR1cm4odW5saXN0KGYpKSAKICB9KX0pCnNyYS4xOS4wMS5yZXAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMTkuMDEucmVwLmxzKSwgZnVuY3Rpb24oaSkgewogIG5hbWVzKHNyYS4xOS4wMS5yZXAubHNbW2ldXSkgPC0gbmFtZXMoY3d0LjE5LjAxW1tpXV0pCiAgcmV0dXJuKHNyYS4xOS4wMS5yZXAubHNbW2ldXSkKfSkKbmFtZXMoc3JhLjE5LjAxLnJlcC5scykgPC0gbmFtZXMoZm0ud3QuMTkuMDEpCnNhdmUoc3JhLjE5LjAxLnJlcC5scywgZmlsZSA9ICJzcmEuMTkuMDEucmVwLmxzLlJEYXRhIikKCiMgYXZlcmFnZSByZXBzCnNyYS4xOS4wMS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5LnN1bS5scyksIGZ1bmN0aW9uKGkpIHsKICBmbSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4xOS4wMS5yZXAubHNbW2ldXVtbMV1dKSwgZnVuY3Rpb24oeikgewogICAgZGF0YS5mcmFtZShmbV8wMV9tZWFuID0gbWVhbihzYXBwbHkoc3JhLjE5LjAxLnJlcC5sc1tbaV1dLCAiWyIsIHopLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICBmbV8wMV9zZCA9IHNkKHNhcHBseShzcmEuMTkuMDEucmVwLmxzW1tpXV0sICJbIiwgeiksIG5hLnJtID0gVFJVRSkpCiAgICB9KQogIHJldHVybihiaW5kX3Jvd3MoZm0pKQp9KQpuYW1lcyhzcmEuMTkuMDEubHMpIDwtIG5hbWVzKGZtLnd0LjE5LjAxKQoKIyMgJzAxIGluYwpzcmEuMTkuMDEuaW5jLmxzIDwtIGxhcHBseShmbS53dC4xOS4wMS5pbmMsIGZ1bmN0aW9uKGxzKSB7CiAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgZCA8LSBjKDEwLCAyMCwgMzApCiAgICBmIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgZltbal1dIDwtIHN1bShkZlsxOmRbal0sICJmbV93dCJdKQogICAgICB9IGVsc2UgewogICAgICAgIGZbW2pdXSA8LSBzdW0oZGZbKGRbai0xXSsxKTpkW2pdLCAiZm1fd3QiXSkKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChmKSkgCiAgfSl9KQoKIyAyMDA5CnNyYS4xOS4wOS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5LnN1bS5scyksIGZ1bmN0aW9uKGkpIHsKICBkIDwtIHNyYS4yMDE5LnN1bS5sc1tbaV1dW1sibHlyX2JvdCJdXQogIGYgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgIGlmKGogPT0gMSkgewogICAgICBmW1tqXV0gPC0gc3VtKGZtLnd0LjE5LjA5W1tpXV1bMTpkW2pdLCAiZm1fd3QiXSkKICAgIH0gZWxzZSB7CiAgICAgIGZbW2pdXSA8LSBzdW0oZm0ud3QuMTkuMDlbW2ldXVsoZFtqLTFdKzEpOmRbal0sICJmbV93dCJdKQogICAgfQogIH0KICByZXR1cm4oY2JpbmQoc3JhLjIwMTkuc3VtLmxzW1tpXV0sIGZtXzA5ID0gdW5saXN0KGYpKSkKfSkKbmFtZXMoc3JhLjE5LjA5LmxzKSA8LSBuYW1lcyhzcmEuMTkuMDEubHMpCgojIGNvbWJpbmUKc3JhLjE5LjAxLjA5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjE5LjAxLmxzKSwgZnVuY3Rpb24oaSkgewogIGRhdGEuZnJhbWUoc3JhLjE5LjAxLmxzW1tpXV0sIHNyYS4xOS4wOS5sc1tbaV1dKQp9KQpuYW1lcyhzcmEuMTkuMDEuMDkubHMpIDwtIG5hbWVzKHNyYS4xOS4wMS5scykKCiMjIGNyZWF0ZSB0aWR5IGNvbWJpbmVkICcwMSwgJzA5LCAnMTkgZGF0YSBmcmFtZQpzcmEuMTkuMDEuMDkuZGYgPC0gYmluZF9yb3dzKHNyYS4xOS4wMS4wOS5scykKc3JhLjE5LjAxLjA5IDwtIHNyYS4xOS4wMS4wOS5kZlssIG5tc10Kc3JhLjE5LjAxLjA5IDwtIHJiaW5kKGRhdGEuZnJhbWUoc3JhLjE5LjAxLjA5Wywgbm1zWzE6NV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbSA9IHNyYS4xOS4wMS4wOS5kZiRmbV8wMV9tZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbV9zZCA9IHNyYS4xOS4wMS4wOS5kZiRmbV8wMV9zZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9IGFzLmNoYXJhY3RlcigyMDAxKSksCiAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoc3JhLjE5LjAxLjA5Wywgbm1zWzE6NV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtID0gc3JhLjE5LjAxLjA5LmRmJGZtXzA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtX3NkID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9IGFzLmNoYXJhY3RlcigyMDA5KSksCiAgICAgICAgICAgICAgICAgICAgIGNiaW5kKHNyYS4xOS4wMS4wOSwgWWVhciA9IGFzLmNoYXJhY3RlcigyMDE5KSkpCgojIGNhbGMgZDE0YyBmcm9tIGZtCnNyYS4xOS4wMS4wOSRkMTRjIDwtIGNhbGNfMTRjKHNyYS4xOS4wMS4wOSRmbSwgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3JhLjE5LjAxLjA5JFllYXIpKSkKc3JhLjE5LjAxLjA5JGQxNGNfc2QgPC0gYWJzKHNyYS4xOS4wMS4wOSRkMTRjIC0gY2FsY18xNGMoc3JhLjE5LjAxLjA5JGZtICsgc3JhLjE5LjAxLjA5JGZtX3NkLCBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzcmEuMTkuMDEuMDkkWWVhcikpKSkKc2F2ZShzcmEuMTkuMDEuMDksIGZpbGUgPSAic3JhLjE5LjAxLjA5LlJEYXRhIikKYGBgCgpgYGB7ciBwbG90LTAxLTA5LTE5LTE0Yy1wcm9maWxlc30KZmlnLm4gPC0gZmlnLm4gKyAxCnNyYS4wMS4wOS4xOSAlPiUKICBtdXRhdGUoUE1lY29feWVhciA9IHBhc3RlMChQTWVjbywgWWVhciksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpICU+JQogICMgZmlsdGVyKFllYXIgIT0gIjIwMDkiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBsaW5ldHlwZSA9IFllYXIsIGdyb3VwID0gUE1lY29feWVhcikpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoYWVzKGFscGhhID0gWWVhciksIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IFllYXIpKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMC42LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9IDAuMykpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAic29saWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gImRvdHRlZCIpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIFRpbWUgc2VyaWVzIG9mIGJ1bGsgc29pbCAkXERlbHRhJF4xNF5DIGJ5IDIwMDEgZGVwdGhzICgyMDAxLCAyMDA5LCAyMDE5IHNhbXBsZXMpKioKCj4qQ2FwdGlvbjoqIFBvaW50cyBmb3IgMjAwMSBzYW1wbGVzIHNob3cgdGhlIG1lYW4gJFxEZWx0YSReMTReQyB2YWx1ZXMgYXQgdGhlIG1lYXN1cmVkIGRlcHRocy4gUG9pbnRzIGZvciAyMDA5IGFuZCAyMDE5IHNhbXBsZXMgYXJlIHNwbGluZS1maXR0ZWQgZXN0aW1hdGVzIG9mICRcRGVsdGEkXjE0XkMgcHJlZGljdGVkIGZvciB0aGUgc2FtZSBkZXB0aCBpbnRlcnZhbHMgYXMgbWVhc3VyZWQgaW4gMjAwMS4gRXJyb3IgYmFycyBzaG93IMKxIDEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBtZWFuIG9mIHRocmVlIHJlcGxpY2F0ZSBwcm9maWxlcyBmb3IgMjAwMSBhbmQgMjAxOSBzYW1wbGVzIChvbmx5IGEgc2luZ2xlIHByb2ZpbGUgd2FzIGFuYWx5emVkIGluIDIwMDkpLiAKCmBgYHtyIHBsb3QtMTktMDEtMDktMTRjLXByb2ZpbGVzfQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjE5LjAxLjA5ICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgbGluZXR5cGUgPSBZZWFyLCBncm91cCA9IFBNZWNvX3llYXIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KGFlcyhhbHBoYSA9IFllYXIpLCBzaXplID0gMykgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBZZWFyKSkgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgIyBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYygzMCwgMCkpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMC42LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9IDAuMykpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAic29saWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDA5IiA9ICJkYXNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9ICJkb3R0ZWQiKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBUaW1lIHNlcmllcyBvZiBidWxrIHNvaWwgJFxEZWx0YSReMTReQyBieSBkZXB0aCAoc3BsaW5lZCB0byAyMDE5IGRlcHRocykqKgoKPipDYXB0aW9uOiogUG9pbnRzIGZvciAyMDE5IHNhbXBsZXMgc2hvdyB0aGUgbWVhbiAkXERlbHRhJF4xNF5DIHZhbHVlcyBhdCB0aGUgbWVhc3VyZWQgZGVwdGhzLiBQb2ludHMgZm9yIDIwMDEgYW5kIDIwMDkgc2FtcGxlcyBhcmUgc3BsaW5lLWZpdHRlZCBlc3RpbWF0ZXMgb2YgJFxEZWx0YSReMTReQyBwcmVkaWN0ZWQgZm9yIHRoZSBzYW1lIGRlcHRoIGludGVydmFscyBhcyBtZWFzdXJlZCBpbiAyMDE5LiBFcnJvciBiYXJzIHNob3cgwrEgMSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1lYW4gb2YgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGZvciAyMDAxIGFuZCAyMDE5IHNhbXBsZXMgKG9ubHkgYSBzaW5nbGUgcHJvZmlsZSB3YXMgYW5hbHl6ZWQgaW4gMjAwOSkuIAo+Kk5COiBPbmx5IHR3byBkZXB0aCBpbnRlcnZhbHMgd2VyZSBtZWFzdXJlZCBhdCB0aGUgY29vbCBhbmQgY29sZCBhbmRlc2l0ZSBzaXRlcyAobWF4IGRlcHRoIG9mIDI3IGFuZCAyOCBjbSwgcmVzcGVjdGl2ZWx5KSwgc28gbGluZWFyIGV4dHJhcG9sYXRpb24gKHVzaW5nIHRoZSBzbG9wZSBvZiB0aGUgbGFzdCAxY20gc3BsaW5lLWZpdHRlZCBkZXB0aCBpbmNyZW1lbnQpIHdhcyB1c2VkIHRvIGV4dGVuZCB0aGUgcHJvZmlsZXMgdG8gMzAgY20uKgoKYGBge3IgcGxvdC1ieS1kZXB0aC0xNEMtdGltZXNlcmllc30KIyBwbG90IGluZGl2aWR1YWwgZGVwdGhzCmZpZy5uIDwtIGZpZy5uICsgMQoKIyBBdG0KYXRtLjE0YyA8LSBkYXRhLmZyYW1lKHllYXIgPSBEYXRtW0RhdG0kRGF0ZSA+IDIwMDAsICJEYXRlIl0sCiAgICAgICAgICAgICAgICAgICAgICBkMTRjID0gRGF0bVtEYXRtJERhdGUgPiAyMDAwLCAiTkhjMTQiXSkKc2F2ZShhdG0uMTRjLCBmaWxlID0gImF0bS4xNGMuUkRhdGEiKQoKIyBidWxrIDE0QyBvdmVyIHRpbWUgZm9yIDAtMTAsIDEwLTIwLCAyMC0zMCB3LyBhdG0Kc3JhLjE5LjAxLjA5ICU+JQogIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogIG11dGF0ZShQTWVjb19kZXB0aCA9IHBhc3RlMChQTWVjbywgbHlyX2JvdCksCiAgICAgICAgIGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgZDE0Y191ID0gZDE0YyArIGQxNGNfc2QsCiAgICAgICAgIGQxNGNfbCA9IGQxNGMgLSBkMTRjX3NkLAogICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpLAogICAgICAgICB5ZWFyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoWWVhcikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHllYXIsIGQxNGMpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY28pLCBzaXplID0gMykgKwogIGdlb21fcGF0aChhZXMoY29sb3IgPSBwbSwgZ3JvdXAgPSBQTWVjb19kZXB0aCwgbGluZXR5cGUgPSBkZXB0aCksIGFscGhhID0gMC4zKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gZDE0Y19sLCAKICAgICAgICB5bWF4ID0gZDE0Y191LAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIHdpZHRoID0gLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIkRlcHRoIChjbSkiLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIxMCIgPSAiMC0xMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwIiA9ICIxMC0yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMwIiA9ICIyMC0zMCIpLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCIxMCIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMCIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzMCIgPSAzKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKCJZZWFyIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCgojIyMgaW5jdWJhdGlvbgojIyAyMDE5CnNyYS4yMDE5LmluYy5kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KHNyYS4yMDE5LmluYy5scywgZnVuY3Rpb24oZGYpIHsKICBkYXRhLmZyYW1lKGRmICU+JQogICAgICAgICAgICAgICBncm91cF9ieShZZWFyLCBQTSwgRUNPLCBseXJfYm90LCBQTWVjbykgJT4lCiAgICAgICAgICAgICAgIHN1bW1hcml6ZSgKICAgICAgICAgICAgICAgICBhY3Jvc3MoLmNvbHMgPSBkMTRjLCAKICAgICAgICAgICAgICAgICAgICAgICAgLmZucyA9IGxpc3QobWVhbiA9IG1lYW4sIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkpICU+JQogICAgICAgICAgICAgICByZW5hbWUoeWVhciA9IFllYXIsIGQxNGMgPSBkMTRjX21lYW4pKQp9KSkKc2F2ZShzcmEuMjAxOS5pbmMuZGYsIGZpbGUgPSAic3JhLjIwMTkuaW5jLmRmLlJEYXRhIikKIyMgMjAwMQpzcmEuMTkuMDEuaW5jLmRmIDwtIGJpbmRfcm93cyhsYXBwbHkoc2VxX2Fsb25nKHNyYS4xOS4wMS5pbmMubHMpLCBmdW5jdGlvbihpKSB7CiAgUE1lY28gPC0gbmFtZXMoc3JhLjE5LjAxLmluYy5scylbaV0KICBkMTRjLmxzIDwtIGxhcHBseShzcmEuMTkuMDEuaW5jLmxzW1tpXV0sIGNhbGNfMTRjLCBvYnNfZGF0ZV95ID0gMjAwMSkKICBkZiA8LSBkYXRhLmZyYW1lKGQxNGMgPSBkMTRjLmxzW1sxXV0sCiAgICAgICAgICAgICAgICAgICBkMTRjX21pbiA9IGQxNGMubHNbWzJdXSwKICAgICAgICAgICAgICAgICAgIGQxNGNfbWF4ID0gZDE0Yy5sc1tbM11dLAogICAgICAgICAgICAgICAgICAgbHlyX2JvdCA9IGMoMTAsIDIwLCAzMCksCiAgICAgICAgICAgICAgICAgICBQTWVjbyA9IFBNZWNvLAogICAgICAgICAgICAgICAgICAgUE0gPSBzdWJzdHIoUE1lY28sIDEsIDIpLAogICAgICAgICAgICAgICAgICAgRUNPID0gc3Vic3RyKFBNZWNvLCAzLCA0KSwKICAgICAgICAgICAgICAgICAgIHllYXIgPSAyMDAxKQogIHJldHVybihkZikKfSkpCnNhdmUoc3JhLjE5LjAxLmluYy5kZiwgZmlsZSA9ICJzcmEuMTkuMDEuaW5jLmRmLlJEYXRhIikKIyBqb2luCnNyYS4xOS4wMS5pbmMgPC0gcmJpbmQoc3JhLjE5LjAxLmluYy5kZiwgc3JhLjIwMTkuaW5jLmRmKQoKIyBwbG90CnNyYS4xOS4wMS5pbmMgJT4lCiAgbXV0YXRlKFBNZWNvX2RlcHRoID0gcGFzdGUwKFBNZWNvLCBseXJfYm90KSwKICAgICAgICAgZGVwdGggPSBmYWN0b3IobHlyX2JvdCksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHllYXIsIGQxNGMpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBlY28sIHNoYXBlID0gZWNvKSwgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzcmEuMjAxOS5pbmMuTC5kZiwgYWVzKGNvbG9yID0gZWNvKSwgc2hhcGUgPSA4LCBzaXplID0gMywgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fcGF0aChhZXMoY29sb3IgPSBlY28sIGdyb3VwID0gUE1lY28pLCBhbHBoYSA9IDAuMykgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1pbiA9IGQxNGNfbWluLCAKICAgICAgICB5bWF4ID0gZDE0Y19tYXgsCiAgICAgICAgY29sb3IgPSBlY28pLCAKICAgIHdpZHRoID0gLjUpICsKICBnZW9tX2Vycm9yYmFyKAogICAgZGF0YSA9IHNyYS4yMDE5LmluYy5MLmRmLAogICAgYWVzKHltaW4gPSBkMTRjX21pbiwgCiAgICAgICAgeW1heCA9IGQxNGNfbWF4LAogICAgICAgIGNvbG9yID0gZWNvKSwgCiAgICB3aWR0aCA9IC41KSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC00MCwgMTcwKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMocG0pLCBjb2xzID0gdmFycyhkZXB0aCkpICsKICB5bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoIlllYXIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdCBpbmMgYW5kIGJ1bGsgdG9nZXRoZXIsIGJ5IGRlcHRoCnNyYS50cy5hbGwgPC0gc3JhLjE5LjAxLjA5ICU+JQogIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogIHNlbGVjdChZZWFyLCBQTSwgRUNPLCBQTWVjbywgbHlyX2JvdCwgZDE0YywgZDE0Y19zZCkgJT4lCiAgbXV0YXRlKFR5cGUgPSAiYnVsayIsCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgeWVhciA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFllYXIpKSkgJT4lCiAgc2VsZWN0KC1kMTRjX3NkLCAtWWVhcikgJT4lCiAgYmluZF9yb3dzKC4sCiAgICAgICAgICAgIHNyYS4xOS4wMS5pbmMgJT4lCiAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIFBNLCBFQ08sIFBNZWNvLCBseXJfYm90LCBkMTRjLCBkMTRjX21pbiwgZDE0Y19tYXgpICU+JQogICAgICAgICAgICAgIHJlbmFtZShkMTRjX2wgPSBkMTRjX21pbiwKICAgICAgICAgICAgICAgICAgICAgZDE0Y191ID0gZDE0Y19tYXgpICU+JQogICAgICAgICAgICAgIG11dGF0ZShUeXBlID0gImluYyIpCiAgKSAlPiUKICBtdXRhdGUoZGVwdGggPSBmYWN0b3IobHlyX2JvdCksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpLAogICAgICAgICBlY29UeXBlID0gcGFzdGUwKGVjbywgIiAoIiwgVHlwZSwgIikiKSkKCiMgUGxvdCBieSBkZXB0aApwbG90LnRzLmZ4IDwtIGZ1bmN0aW9uKGRmKSB7CiAgZGYgJT4lCiAgICBmaWx0ZXIoZDE0YyA+IC0yMDApICU+JQogICAgZmlsdGVyKHllYXIgIT0gMjAwOSkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHllYXIsIGQxNGMpKSArCiAgICBnZW9tX3BhdGgoZGF0YSA9IGF0bS4xNGMpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvVHlwZSksIHNpemUgPSAzKSArCiAgICBnZW9tX3BhdGgoYWVzKGNvbG9yID0gcG0sIGxpbmV0eXBlID0gVHlwZSksIGFscGhhID0gMC4zKSArCiAgICBnZW9tX2Vycm9yYmFyKAogICAgICBhZXMoeW1pbiA9IGQxNGNfbCwgCiAgICAgICAgICB5bWF4ID0gZDE0Y191LAogICAgICAgICAgY29sb3IgPSBwbSksIAogICAgICB3aWR0aCA9IC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0gKHR5cGUpIiwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIChpbmMpIiA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoaW5jKSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKGluYykiID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtIChidWxrKSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIChidWxrKSIgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIChidWxrKSIgPSAxNykpICsKICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgICB5bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogICAgeGxhYigiWWVhciIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKfQoKIyBwbG90cwpsYXBwbHkoc3BsaXQoc3JhLnRzLmFsbCwgc3JhLnRzLmFsbCRkZXB0aCksIHBsb3QudHMuZngpCgojICMgdG8gc2F2ZQojIGZvcihpIGluIDE6MykgZ2dzYXZlKHBhc3RlMChpLCAiLnBkZiIpLCBsYXBwbHkoc3BsaXQoc3JhLnRzLmFsbCwgc3JhLnRzLmFsbCRkZXB0aCksIHBsb3QudHMuZngpW1tpXV0pCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBDaGFuZ2UgaW4gJFxEZWx0YSReMTReQyBvZiBidWxrIHNvaWwgKHBhbmVsIGEpIGFuZCByZXNwaXJlZCBDT34yfiAocGFuZWwgYikgb3ZlciB0aW1lIHJlbGF0aXZlIHRvIHRoZSBhdG1vc3BoZXJlKioKCj4qQ2FwdGlvbjoqIFBvaW50cyBmb3IgMjAxOSBzYW1wbGVzIHNob3cgdGhlIG1lYW4gJFxEZWx0YSReMTReQyB2YWx1ZXMgYXQgdGhlIG1lYXN1cmVkIGRlcHRocy4gUG9pbnRzIGZvciAyMDAxIGFuZCAyMDA5IChidWxrIG9ubHkpIHNhbXBsZXMgYXJlIHNwbGluZS1maXR0ZWQgZXN0aW1hdGVzIG9mICRcRGVsdGEkXjE0XkMgcHJlZGljdGVkIGZvciB0aGUgc2FtZSBkZXB0aCBpbnRlcnZhbHMgYXMgbWVhc3VyZWQgaW4gMjAxOS4gRXJyb3IgYmFycyBmb3IgYnVsayBzYW1wbGVzIGluIHBhbmVsIChhKSBzaG93IMKxIDEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBtZWFuIG9mIHRocmVlIHJlcGxpY2F0ZSBwcm9maWxlcyBmb3IgMjAwMSBhbmQgMjAxOSBzYW1wbGVzIChvbmx5IGEgc2luZ2xlIHByb2ZpbGUgd2FzIGFuYWx5emVkIGluIDIwMDkpOyBlcnJvciBiYXJzIGZvciBpbmN1YmF0aW9uIHNhbXBsZXMgaW4gcGFuZWwgKGIpIHNob3cgdGhlIHZhbHVlcyBvZiB0aGUgdHdvIHJlcHMsIHdoaWxlIHRoZSBwb2ludCByZXByZXNlbnRzIHRoZSBtZWFuLiAKPipOQjogT25seSB0d28gZGVwdGggaW50ZXJ2YWxzIHdlcmUgbWVhc3VyZWQgYXQgdGhlIGNvb2wgYW5kIGNvbGQgYW5kZXNpdGUgc2l0ZXMgKG1heCBkZXB0aCBvZiAyNyBhbmQgMjggY20sIHJlc3BlY3RpdmVseSksIHNvIGxpbmVhciBleHRyYXBvbGF0aW9uICh1c2luZyB0aGUgc2xvcGUgb2YgdGhlIGxhc3QgMWNtIHNwbGluZS1maXR0ZWQgZGVwdGggaW5jcmVtZW50KSB3YXMgdXNlZCB0byBleHRlbmQgdGhlIHByb2ZpbGVzIHRvIDMwIGNtLioKCmBgYHtyIG1pbi1kYXRhLXJhczE4fQojIGxvYWQgZGF0YQpyYXMxOC5taW4gPC0gcmVhZF9leGNlbCgiL1VzZXJzL2plZmYvc3JhLXRzL2RhdGEvZXh0ZXJuYWwvc3JhX3Jhc19zdW0vc2llcnJhX2RhdGFfc3VtbWFyeV8yMDIwLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJEYXRhX1N1bW1hcnlfMjAxOF9wYXBlciIpCnJhczE4Lmx5ciA8LSByZWFkX2V4Y2VsKCIvVXNlcnMvamVmZi9zcmEtdHMvZGF0YS9leHRlcm5hbC9zcmFfcmFzX3N1bS9zaWVycmFfZGF0YV9zdW1tYXJ5XzIwMjAueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIjIwMDlfYnVsa19kYXRhIikKcmFzMTguZnJjIDwtIHJlYWRfZXhjZWwoIi9Vc2Vycy9qZWZmL3NyYS10cy9kYXRhL2V4dGVybmFsL3NyYV9yYXNfc3VtL3NpZXJyYV9kYXRhX3N1bW1hcnlfMjAyMC54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiMjAwOV9mcmFjdGlvbl9kYXRhIikKCiMgam9pbiBkYXRhCm5tcyA8LSBuYW1lcyhyYXMxOC5taW4pW3doaWNoKG5hbWVzKHJhczE4Lm1pbikgJWluJSBuYW1lcyhyYXMxOC5seXIpKV0Kbm1zIDwtIG5tc1std2hpY2gobm1zID09ICJJRF9zcmEiKV0KcmFzMTgubWluIDwtIHJhczE4Lm1pblsgLCAtd2hpY2gobmFtZXMocmFzMTgubWluKSAlaW4lIG5tcyldCnJhczE4IDwtIHR5cGUuY29udmVydChtZXJnZShyYXMxOC5seXIsIHJhczE4Lm1pbikpCgojIHNwbGluZSBmaXRzCnJhczE4LnNwbGl0IDwtIHNwbGl0KHJhczE4XzIsIHJhczE4XzIkbWlucylbYygxLCAzOjUpXQpyYXMxOC5zcCA8LSBsYXBwbHkocmFzMTguc3BsaXQsIGZ1bmN0aW9uKGRmKSB7CiAgbHMgPC0gbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIGRlcHRocyh4KSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgICB4Lm1wcyA8LSBtcHNwbGluZSh4LCB2YXIubmFtZSA9ICJjb25jIiwgZCA9IHQoc2VxKDAsIDEwMCwgMTApKSkKICAgIHJldHVybih4Lm1wcyR2YXIuc3RkKQogIH0pCiAgbmFtZXMobHMpIDwtIHVuaXF1ZShkZiRwcm9fbmFtZSkKICByZXR1cm4obHMpCn0pCm5hbWVzKHJhczE4LnNwKSA8LSBjKCJBbF9veCIsICJBbF9weSIsICJGZV9kYyIsICJGZV9veCIpCnJhczE4LnNwLmRmIDwtIGRhdGEuZnJhbWUocmVkdWNlKGxhcHBseShzZXFfYWxvbmcocmFzMTguc3ApLCBmdW5jdGlvbihpKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKHQoYmluZF9yb3dzKHJhczE4LnNwW1tpXV0pKSkKICAgIG5hbWVzKGRmKSA8LSB1bmlxdWUocmFzMTgkcHJvX25hbWUpCiAgICBkZiRkZXB0aCA8LSByb3duYW1lcyhkZikKICAgIHJldHVybihkZiAlPiUKICAgICAgICAgICAgIHBpdm90X2xvbmdlcighZGVwdGgsIG5hbWVzX3RvID0gInByb19uYW1lIiwgdmFsdWVzX3RvID0gbmFtZXMocmFzMTguc3ApW2ldKSkKICB9KSwKICBsZWZ0X2pvaW4sCiAgYnkgPSBjKCJkZXB0aCIsICJwcm9fbmFtZSIpCikpCnJhczE4LnNwLmRmIDwtIHJhczE4LnNwLmRmWy13aGljaChyYXMxOC5zcC5kZiRkZXB0aCA9PSAic29pbCBkZXB0aCIpLCBdCnJhczE4LnNwLmRmJGx5cl9ib3QgPC0gcmVwKHNlcSgxMCwgMTAwLCAxMCksIGVhY2ggPSA5KQpyYXMxOC5zcC5kZiA8LSByYXMxOC5zcC5kZltjb21wbGV0ZS5jYXNlcyhyYXMxOC5zcC5kZiksIF0KcmFzMTguc3AuZGYkUE0gPC0gc3Vic3RyKHJhczE4LnNwLmRmJHByb19uYW1lLCAxLCAyKQpyYXMxOC5zcC5kZiRFQ08gPC0gc3Vic3RyKHJhczE4LnNwLmRmJHByb19uYW1lLCAzLCA0KQpzYXZlKHJhczE4LnNwLmRmLCBmaWxlID0gInJhczE4LnNwLmRmLlJEYXRhIikKCiMgcmVzaGFwZSBzcmEudHMuYWxsIHcvIGJ1bGsgYW5kIGluYyBpbiBzZXBhcmF0ZSBjb2xzCm5tcy5pbmMuYmxrMiA8LSBubXMuaW5jLmJsawpubXMuaW5jLmJsazJbWzRdXSA8LSAieWVhciIKc3JhLnRzLmFsbC5ibGsuaW5jIDwtIG1lcmdlKHNyYS50cy5hbGxbc3JhLnRzLmFsbCRUeXBlID09ICJidWxrIiwgXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYS50cy5hbGxbc3JhLnRzLmFsbCRUeXBlID09ICJpbmMiLCBjKG5tcy5pbmMuYmxrMiwgImQxNGMiLCAiZDE0Y191IiwgImQxNGNfbCIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbm1zLmluYy5ibGsyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VmZml4ZXMgPSBjKCJfYnVsayIsICJfaW5jIikpICU+JQogIGZpbHRlcih5ZWFyICE9IDIwMDkpICU+JQogIG11dGF0ZShibGsuaW5jID0gZDE0Y19idWxrIC0gZDE0Y19pbmMsCiAgICAgICAgIGJsay5pbmMuc2QgPSBzcXJ0KChkMTRjX3VfYnVsayAtIGQxNGNfYnVsayleMiArIGFwcGx5KGNiaW5kKGQxNGNfaW5jLCBkMTRjX3VfaW5jLCBkMTRjX2xfaW5jKSwgMSwgdmFyKSkpCgojIGpvaW4gdy8gZDE0YwpzcmEuYWxsLm1pbiA8LSByYXMxOC5zcC5kZiAlPiUKICBtdXRhdGUocG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSwKICAgICAgICAgZWNvID0gaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSkgJT4lCiAgIyBtdXRhdGUoQWxfbm9uQ3J5cyA9IEFsX294IC0gQWxfcHksCiAgIyAgICAgICAgRmVfQ3J5cyA9IEZlX2RjIC0gRmVfb3gpICU+JQogIHNlbGVjdCgtUE0sIC1FQ08sIC1wcm9fbmFtZSkgJT4lCiAgbGVmdF9qb2luKHNyYS50cy5hbGwuYmxrLmluY1sgLCBjKCJwbSIsICJlY28iLCAibHlyX2JvdCIsICJ5ZWFyIiwgImQxNGNfYnVsayIsICJkMTRjX3VfYnVsayIsICJkMTRjX2luYyIsICJkMTRjX3VfaW5jIiwgImQxNGNfbF9pbmMiLCAiZDE0Y19sX2J1bGsiLCAiYmxrLmluYyIsICJibGsuaW5jLnNkIildLCAKICAgICAgICAgICAgLiwgCiAgICAgICAgICAgIGJ5ID0gYygicG0iLCAiZWNvIiwgImx5cl9ib3QiKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJBbF9weSIsICJBbF9veCIsICJGZV9veCIsICJGZV9kYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAjICJBbF9ub25DcnlzIiwgIkZlX0NyeXMiCiAgICAgICAgICAgICAgICAgICAgICAgICksIG5hbWVzX3RvID0gIm1pbiIsIHZhbHVlc190byA9ICJjb25jIikKCiMgc2F2ZQpzYXZlKHNyYS5hbGwubWluLCBmaWxlID0gInNyYS5hbGwubWluLlJEYXRhIikKYGBgCgpgYGB7ciBwbG90LW1pbi0xNGN9CiMgYnVsawpzcmEuYWxsLm1pbiAlPiUKICBtdXRhdGUocG1FY29EZXB0aCA9IHBhc3RlMChwbSwgZWNvLCBseXJfYm90KSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIiksCiAgICAgICAgIHdpZHRoID0gaWZlbHNlKG1pbiA9PSAiQWxfcHkiIHwgbWluID09ICJGZV9veCIsIC4zLCAxLjUpKSAlPiUKICBmaWx0ZXIocG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQzMCIgJiBwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDIwIikgJT4lCiAgZ2dwbG90KC4sIGFlcyhjb25jLCBkMTRjX2J1bGspKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBzaXplID0gZGVwdGgpKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gZDE0Y19sX2J1bGssCiAgICAgICAgeW1heCA9IGQxNGNfdV9idWxrLAogICAgICAgIGNvbG9yID0gcG0sCiAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUgKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgc2NhbGVfc2l6ZV9tYW51YWwobmFtZSA9ICJEZXB0aCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gKDM6NSkpICsKICBmYWNldF93cmFwKHZhcnMobWluKSwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgaW5jCnNyYS5hbGwubWluICU+JQogIG11dGF0ZShwbUVjb0RlcHRoID0gcGFzdGUwKHBtLCBlY28sIGx5cl9ib3QpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSwKICAgICAgICAgd2lkdGggPSBpZmVsc2UobWluID09ICJBbF9weSIgfCBtaW4gPT0gIkZlX294IiwgLjMsIDEuNSkpICU+JQogIGZpbHRlcihwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDMwIiAmIHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMjAiKSAlPiUKICBmaWx0ZXIobHlyX2JvdCA9PSAzMCkgJT4lCiAgZ2dwbG90KC4sIGFlcyhjb25jLCBkMTRjX2luYykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1llYXIsIHNpemUgPSBkZXB0aCkpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltaW4gPSBkMTRjX2xfaW5jLAogICAgICAgIHltYXggPSBkMTRjX3VfaW5jLAogICAgICAgIGNvbG9yID0gcG0sCiAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUgKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgc2NhbGVfc2l6ZV9tYW51YWwobmFtZSA9ICJEZXB0aCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gKDM6NSkpICsKICBmYWNldF93cmFwKHZhcnMobWluKSwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgYnVsay1pbmMKc3JhLmFsbC5taW4gJT4lCiAgbXV0YXRlKHBtRWNvRGVwdGggPSBwYXN0ZTAocG0sIGVjbywgbHlyX2JvdCksCiAgICAgICAgIGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCB5ZWFyLCAiKSIpLAogICAgICAgICB3aWR0aCA9IGlmZWxzZShtaW4gPT0gIkFsX3B5IiB8IG1pbiA9PSAiRmVfb3giLCAuMywgMS41KSkgJT4lCiAgZmlsdGVyKHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMzAiICYgcG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQyMCIpICU+JQogIGdncGxvdCguLCBhZXMoY29uYywgYmxrLmluYykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1llYXIsIHNpemUgPSBkZXB0aCkpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltaW4gPSBibGsuaW5jIC0gYmxrLmluYy5zZCwKICAgICAgICB5bWF4ID0gYmxrLmluYyArIGJsay5pbmMuc2QsCiAgICAgICAgY29sb3IgPSBwbSwKICAgICAgICB3aWR0aCA9IHdpZHRoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDAxKSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKDIwMTkpIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKICBzY2FsZV9zaXplX21hbnVhbChuYW1lID0gIkRlcHRoIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAoMzo1KSkgKwogIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKICB5bGFiKGV4cHJlc3Npb24oJ0J1bGsgLSBSZXNwaXJlZCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBGZV9kYyBhbG9uZQojIyMjIwojIHdhcm0Kc3JhLmFsbC5taW4gJT4lCiAgZmlsdGVyKGVjbyA9PSAid2FybSIgJiBtaW4gPT0gIkZlX2RjIikgJT4lCiAgbXV0YXRlKGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCB5ZWFyLCAiKSIpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGNvbmMsIGJsay5pbmMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBzaXplID0gZGVwdGgpKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAogICAgICAgIGNvbG9yID0gcG0pLAogICAgICAgIHdpZHRoID0gMS41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwKSkgKwogIHNjYWxlX3NpemVfbWFudWFsKG5hbWUgPSAiRGVwdGgiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9ICgzOjUpKSArCiAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwogIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbignQ29uY2VudHJhdGlvbiAoZyBrZydeLTEqJyknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGNvb2wgKyBjb2xkCnNyYS5hbGwubWluICU+JQogIGZpbHRlcihlY28gIT0gIndhcm0iICYgbWluID09ICJGZV9kYyIpICU+JQogIG11dGF0ZShwbUVjb0RlcHRoID0gcGFzdGUwKHBtLCBlY28sIGx5cl9ib3QpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSkgJT4lCiAgZmlsdGVyKHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMzAiICYgcG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQyMCIpICU+JQogIGdncGxvdCguLCBhZXMoY29uYywgYmxrLmluYykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1llYXIsIHNpemUgPSBkZXB0aCkpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltaW4gPSBibGsuaW5jIC0gYmxrLmluYy5zZCwKICAgICAgICB5bWF4ID0gYmxrLmluYyArIGJsay5pbmMuc2QsCiAgICAgICAgY29sb3IgPSBwbSksCiAgICAgICAgd2lkdGggPSAuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKICBzY2FsZV9zaXplX21hbnVhbChuYW1lID0gIkRlcHRoIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAoMzo1KSkgKwogIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKICB5bGFiKGV4cHJlc3Npb24oJ0J1bGsgLSBSZXNwaXJlZCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQojIyMjIwoKIyMgYnkgZGVwdGgKIyMjIyMKIyAjIDEwIGNtCiMgc3JhLmFsbC5taW4gJT4lCiMgICBtdXRhdGUoZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIiksCiMgICAgICAgICAgd2lkdGggPSBpZmVsc2UobWluID09ICJBbF9weSIgfCBtaW4gPT0gIkZlX294IiwgLjMsIDEuNSkpICU+JQojICAgZmlsdGVyKGx5cl9ib3QgPT0gMTApICU+JQojICAgZ2dwbG90KC4sIGFlcyhjb25jLCBibGsuaW5jKSkgKwojICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyKSwgc2l6ZSA9IDMpICsKIyAgIGdlb21fZXJyb3JiYXIoCiMgICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiMgICAgICAgICB5bWF4ID0gYmxrLmluYyArIGJsay5pbmMuc2QsCiMgICAgICAgICBjb2xvciA9IHBtLAojICAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiMgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwojICAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwojICAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyAKIyAjIDIwIGNtCiMgc3JhLmFsbC5taW4gJT4lCiMgICBtdXRhdGUocG1FY29EZXB0aCA9IHBhc3RlMChwbSwgZWNvLCBseXJfYm90KSwKIyAgICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSwKIyAgICAgICAgICB3aWR0aCA9IGlmZWxzZShtaW4gPT0gIkFsX3B5IiB8IG1pbiA9PSAiRmVfb3giLCAuMywgMS41KSkgJT4lCiMgICBmaWx0ZXIocG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQyMCIpICU+JQojICAgZmlsdGVyKGx5cl9ib3QgPT0gMjApICU+JQojICAgZ2dwbG90KC4sIGFlcyhjb25jLCBibGsuaW5jKSkgKwojICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyKSwgc2l6ZSA9IDMpICsKIyAgIGdlb21fZXJyb3JiYXIoCiMgICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiMgICAgICAgICB5bWF4ID0gYmxrLmluYyArIGJsay5pbmMuc2QsCiMgICAgICAgICBjb2xvciA9IHBtLAojICAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiMgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwojICAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwojICAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyAKIyAjIDMwIGNtCiMgc3JhLmFsbC5taW4gJT4lCiMgICBtdXRhdGUocG1FY29EZXB0aCA9IHBhc3RlMChwbSwgZWNvLCBseXJfYm90KSwKIyAgICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSwKIyAgICAgICAgICB3aWR0aCA9IGlmZWxzZShtaW4gPT0gIkFsX3B5IiB8IG1pbiA9PSAiRmVfb3giLCAuMywgMS41KSkgJT4lCiMgICBmaWx0ZXIocG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQzMCIpICU+JQojICAgZmlsdGVyKGx5cl9ib3QgPT0gMzApICU+JQojICAgZ2dwbG90KC4sIGFlcyhjb25jLCBibGsuaW5jKSkgKwojICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyKSwgc2l6ZSA9IDMpICsKIyAgIGdlb21fZXJyb3JiYXIoCiMgICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiMgICAgICAgICB5bWF4ID0gYmxrLmluYyArIGJsay5pbmMuc2QsCiMgICAgICAgICBjb2xvciA9IHBtLAojICAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiMgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwojICAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwojICAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7ciB0cy1zdGF0c30KIyBmdW5jdGlvbiBmb3IgVHVrZXkgSFNEIHRhYmxlcwp0dWtleS50YWJsZS5meCA8LSBmdW5jdGlvbih4LCB5ZWFyLCB0eXBlLCB2YXIpIHsKICBkZXB0aCA8LSBwYXN0ZTAodW5pcXVlKHgkbHlyX2JvdCkgLSAxMCwgIi0iLCB1bmlxdWUoeCRseXJfYm90KSwgIiBjbSIpCiAgaWYgKHR5cGUgPT0gImluYyIpIHsKICAgIHggPC0geFt4JGQxNGMgPiAtMjAwLCBjKCJkMTRjIiwgdmFyKV0KICB9IAogIHJldHVybigKICAgIFR1a2V5SFNEKGFvdihyZWZvcm11bGF0ZSh2YXIsICJkMTRjIiksIHgpKVt2YXJdICU+JQogICAgZGF0YS5mcmFtZSguKSAlPiUKICAgIG11dGF0ZShQYWlycyA9IHJvd25hbWVzKC4pKSAlPiUKICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCAzKSkgJT4lCiAgICBndCgpICU+JQogICAgdGFiX2hlYWRlcigKICAgICAgdGl0bGUgPSBkZXB0aCwKICAgICAgc3VidGl0bGUgPSBwYXN0ZSh5ZWFyLCB0eXBlLCB2YXIpCiAgICApKQp9CgojIyMgMjAwMQojIyBidWxrCnNyYS4yMDAxLmJ1bGsuZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShzcmEuMTkuMDEucmVwLmxzLCBmdW5jdGlvbihscykgewogICAgbHMgPC0gbGFwcGx5KGxzLCBmdW5jdGlvbih4KSB4W2NvbXBsZXRlLmNhc2VzKHgpXSkKICAgIGQxNGMgPC0gY2FsY18xNGModW5saXN0KGxzKSwgMjAwMSkKICAgIGRmIDwtIGRhdGEuZnJhbWUoZDE0YyA9IGQxNGMsCiAgICAgICAgICAgICAgICAgICAgIGx5cl9ib3QgPSByZXAoYygxMCwgMjAsIDMwKSwgbGVuZ3RoKGQxNGMpIC8gMykpCiAgICByZXR1cm4oZGYpCiAgfSksCiAgLmlkID0gIlBNZWNvIikgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvLCAxLCAyKSwKICAgICAgICAgRUNPID0gc3Vic3RyKFBNZWNvLCAzLCA0KSkKIyBQTQojIGxhcHBseShzcGxpdChzcmEuMjAwMS5idWxrLmRmLCBzcmEuMjAwMS5idWxrLmRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiMgICBzdW1tYXJ5KGxtKGQxNGMgfiBQTSwgeCkpCiMgfSkKbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmJ1bGsuZGYsIHNyYS4yMDAxLmJ1bGsuZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICB0dWtleS50YWJsZS5meCh4LCAiMjAwMSIsICJidWxrIiwgIlBNIikKfSkKIyBFQ08KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMDEuYnVsay5kZiwgc3JhLjIwMDEuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgc3VtbWFyeShsbShkMTRjIH4gRUNPLCB4KSkKIyB9KQpsYXBwbHkoc3BsaXQoc3JhLjIwMDEuYnVsay5kZiwgc3JhLjIwMDEuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogIHR1a2V5LnRhYmxlLmZ4KHgsICIyMDAxIiwgImJ1bGsiLCAiRUNPIikKfSkKCiMjIGluYwpzcmEuMjAwMS5pbmMuZGYyIDwtIGNiaW5kKHNyYS4xOS4wMS5pbmMuZGZbcmVwKDE6bnJvdyhzcmEuMTkuMDEuaW5jLmRmKSwgMiksIGMoIlBNIiwgIkVDTyIsICJseXJfYm90IildLAogICAgICAgICAgICAgICAgICAgICAgICAgIGQxNGMgPSBjKHNyYS4xOS4wMS5pbmMuZGYkZDE0Y19taW4sIHNyYS4xOS4wMS5pbmMuZGYkZDE0Y19tYXgpKQpzYXZlKHNyYS4yMDAxLmluYy5kZjIsIGZpbGUgPSAic3JhLjIwMDEuaW5jLmRmMi5SRGF0YSIpCiMgUE0KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMDEuaW5jLmRmMiwgc3JhLjIwMDEuaW5jLmRmMiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgc3VtbWFyeShsbShkMTRjIH4gUE0sIHhbeCRkMTRjID4gLTIwMCwgXSkpCiMgfSkKbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmluYy5kZjIsIHNyYS4yMDAxLmluYy5kZjIkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICB0dWtleS50YWJsZS5meCh4LCAiMjAwMSIsICJpbmMiLCAiUE0iKQp9KQojIEVDTwojIGxhcHBseShzcGxpdChzcmEuMjAwMS5pbmMuZGYyLCBzcmEuMjAwMS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiMgICBzdW1tYXJ5KGxtKGQxNGMgfiBFQ08sIHhbeCRkMTRjID4gLTIwMCwgXSkpCiMgfSkKbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmluYy5kZjIsIHNyYS4yMDAxLmluYy5kZjIkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICB0dWtleS50YWJsZS5meCh4LCAiMjAwMSIsICJpbmMiLCAiRUNPIikKfSkKCiMjIyAyMDE5CiMjIGJ1bGsKc3JhLjIwMTkuYnVsay5kZiA8LSBiaW5kX3Jvd3Moc3JhLjIwMTkubHMpCiMgUE0KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuYnVsay5kZiwgc3JhLjIwMTkuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgaWYgKG5yb3coeCkgPT0gMjcpIHN1bW1hcnkobG0oZDE0YyB+IFBNLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAxOS5idWxrLmRmLCBzcmEuMjAxOS5idWxrLmRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgaWYgKG5yb3coeCkgPT0gMjcpIHR1a2V5LnRhYmxlLmZ4KHgsICIyMDE5IiwgImJ1bGsiLCAiUE0iKQp9KQojIEVDTwojIGxhcHBseShzcGxpdChzcmEuMjAxOS5idWxrLmRmLCBzcmEuMjAxOS5idWxrLmRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiMgICBpZiAobnJvdyh4KSA9PSAyNykgc3VtbWFyeShsbShkMTRjIH4gRUNPLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAxOS5idWxrLmRmLCBzcmEuMjAxOS5idWxrLmRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgaWYgKG5yb3coeCkgPT0gMjcpIHR1a2V5LnRhYmxlLmZ4KHgsICIyMDE5IiwgImJ1bGsiLCAiRUNPIikKfSkKIyMgaW5jCnNyYS4yMDE5LmluYy5kZjIgPC0gYmluZF9yb3dzKHNyYS4yMDE5LmluYy5scykKc2F2ZShzcmEuMjAxOS5pbmMuZGYyLCBmaWxlID0gInNyYS4yMDE5LmluYy5kZjIuUkRhdGEiKQojIFBNCiMgbGFwcGx5KHNwbGl0KHNyYS4yMDE5LmluYy5kZjIsIHNyYS4yMDE5LmluYy5kZjIkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKIyAgIHN1bW1hcnkobG0oZDE0YyB+IFBNLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAxOS5pbmMuZGYyLCBzcmEuMjAxOS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgdHVrZXkudGFibGUuZngoeCwgIjIwMTkiLCAiaW5jIiwgIlBNIikKfSkKIyBFQ08KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuaW5jLmRmMiwgc3JhLjIwMTkuaW5jLmRmMiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgc3VtbWFyeShsbShkMTRjIH4gRUNPLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAxOS5pbmMuZGYyLCBzcmEuMjAxOS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgdHVrZXkudGFibGUuZngoeCwgIjIwMTkiLCAiaW5jIiwgIkVDTyIpCn0pCgojIGNvbXBhcmUgMjAwMSBhbmQgMjAxOQojIGJ1bGsKc3JhLjAxLjE5LmJ1bGsuZGYgPC0gZGF0YS5mcmFtZSgKICByYmluZChzcmEuMjAwMS5idWxrLmRmLCAKICAgICAgICBzcmEuMjAxOS5idWxrLmRmWywgd2hpY2gobmFtZXMoc3JhLjIwMTkuYnVsay5kZikgJWluJSBuYW1lcyhzcmEuMjAwMS5idWxrLmRmKSldKSwKICB5ZWFyID0gYXMuZmFjdG9yKGMocmVwKDIwMDEsIG5yb3coc3JhLjIwMDEuYnVsay5kZikpLCByZXAoMjAxOSwgbnJvdyhzcmEuMjAxOS5idWxrLmRmKSkpKSkgJT4lCiAgZmlsdGVyKGx5cl9ib3QgPCAzMSkKc3JhLjAxLjE5LmJ1bGsubHMgPC0gc3BsaXQoc3JhLjAxLjE5LmJ1bGsuZGYsIHNyYS4wMS4xOS5idWxrLmRmJFBNZWNvKQpsYXBwbHkoc3JhLjAxLjE5LmJ1bGsubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogICAgdHVrZXkudGFibGUuZngoeCwgcGFzdGUwKHVuaXF1ZShkZiRQTWVjbyksICIgMjAwMSB2cy4gMjAxOSIpLCAiYnVsayIsICJ5ZWFyIikKICB9KQp9KQojIGJ5IFBNCmxhcHBseShzcGxpdChzcmEuMDEuMTkuYnVsay5kZiwgc3JhLjAxLjE5LmJ1bGsuZGYkUE0pLCBmdW5jdGlvbihkZikgewogIGxhcHBseShzcGxpdChkZiwgZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICAgIHR1a2V5LnRhYmxlLmZ4KHgsIHBhc3RlMCh1bmlxdWUoZGYkUE0pLCAiIDIwMDEgdnMuIDIwMTkiKSwgImJ1bGsiLCAieWVhciIpCiAgfSkKfSkKIyBieSBFQ08KbGFwcGx5KHNwbGl0KHNyYS4wMS4xOS5idWxrLmRmLCBzcmEuMDEuMTkuYnVsay5kZiRFQ08pLCBmdW5jdGlvbihkZikgewogIGxhcHBseShzcGxpdChkZiwgZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICAgIHR1a2V5LnRhYmxlLmZ4KHgsIHBhc3RlMCh1bmlxdWUoZGYkRUNPKSwgIiAyMDAxIHZzLiAyMDE5IiksICJidWxrIiwgInllYXIiKQogIH0pCn0pCiMgaW5jCnNyYS4wMS4xOS5pbmMuZGYgPC0gZGF0YS5mcmFtZSgKICBkMTRjID0gYyhzcmEuMTkuMDEuaW5jWyAsICJkMTRjX21pbiJdLAogICAgICAgICAgIHNyYS4xOS4wMS5pbmNbICwgImQxNGNfbWF4Il0pLAogIHNyYS4xOS4wMS5pbmNbICwgYygiUE1lY28iLCAibHlyX2JvdCIsICJQTSIsICJFQ08iLCAieWVhciIpXSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5mYWN0b3IoeWVhcikpCnNyYS4wMS4xOS5pbmMubHMgPC0gc3BsaXQoc3JhLjAxLjE5LmluYy5kZiwgc3JhLjAxLjE5LmluYy5kZiRQTWVjbykKbGFwcGx5KHNyYS4wMS4xOS5pbmMubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogICAgdHVrZXkudGFibGUuZngoeCwgcGFzdGUwKHVuaXF1ZShkZiRQTWVjbyksICIgMjAwMSB2cy4gMjAxOSIpLCAiaW5jIiwgInllYXIiKQogIH0pCn0pCmxhcHBseShzcGxpdChzcmEuMDEuMTkuaW5jLmRmLCBzcmEuMDEuMTkuaW5jLmRmJFBNKSwgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgICB0dWtleS50YWJsZS5meCh4LCBwYXN0ZTAodW5pcXVlKGRmJFBNKSwgIiAyMDAxIHZzLiAyMDE5IiksICJpbmMiLCAieWVhciIpCiAgfSkKfSkKbGFwcGx5KHNwbGl0KHNyYS4wMS4xOS5pbmMuZGYsIHNyYS4wMS4xOS5pbmMuZGYkRUNPKSwgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgICB0dWtleS50YWJsZS5meCh4LCBwYXN0ZTAodW5pcXVlKGRmJEVDTyksICIgMjAwMSB2cy4gMjAxOSIpLCAiaW5jIiwgInllYXIiKQogIH0pCn0pCmBgYAoKYGBge3IgbWluLTE0Yy1zdGF0c30Kc3JhLjAxLjE5Lm1pbi5yZXBzIDwtIGxlZnRfam9pbigKICBtZXJnZShzcmEuMDEuMTkuYnVsay5kZiwgc3JhLjAxLjE5LmluYy5kZiwKICAgICAgICBieSA9IGMoIlBNZWNvIiwgIlBNIiwgIkVDTyIsICJ5ZWFyIiwgImx5cl9ib3QiKSwKICAgICAgICBzdWZmaXhlcyA9IGMoIl9ibGsiLCAiX2luYyIpKSwKICByYXMxOC5zcC5kZlsgLCBjKCJBbF9veCIsICJBbF9weSIsICJGZV9kYyIsICJGZV9veCIsICJQTSIsICJFQ08iLCAibHlyX2JvdCIpXSwKICBieSA9IGMoIlBNIiwgIkVDTyIsICJseXJfYm90IikpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeWVhcikpKQoKc3VtbWFyeShsbShkMTRjX2JsayB+IEFsX294ICsgbHlyX2JvdCArIHllYXIsIHNyYS4wMS4xOS5taW4ucmVwcykpCnNyYS4wMS4xOS5taW4ucmVwcyAlPiUKICBtdXRhdGUoZWNvID0gaWZlbHNlKEVDTyA9PSAicmYiLCAiY29sZCIsIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAid2FybSIpKSkgJT4lCiAgbXV0YXRlKGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCB5ZWFyLCAiKSIpKSAlPiUKICAjIGZpbHRlcihwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDMwIiAmIHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMjAiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKEFsX294LCBkMTRjX2JsaykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFBNLCBzaGFwZSA9IGVjb1llYXIpLCBzaXplID0gMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9IGdyYW5pdGUpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIikpICsgCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDAxKSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKDIwMTkpIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKICBmYWNldF93cmFwKHZhcnMobHlyX2JvdCkpICsKICB5bGFiKGV4cHJlc3Npb24oJ0J1bGsgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeGxhYihleHByZXNzaW9uKCdPeGFsYXRlIGV4dHJhY3RhYmxlIEFsIChnIGtnJ14tMSonKScpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7ciB0dWtleS1wbG90c30KIyBjb2xvciBwYWxldHRlcyBmb3IgRUNPICYgUE0Kd2FybSA8LSAiI0JGODEyRCIKY29vbCA8LSAiIzgwQ0RDMSIKY29sZCA8LSAiIzAxNjY1RSIKZ3Jhbml0ZSA8LSAiIzlkYWJhOSIKYW5kZXNpdGUgPC0gIiMzODJkYmYiCmJhc2FsdCA8LSAiI2JmMzgyZCIKCiMgcGxvdCBmeApib3hwbG90LmZ4IDwtIGZ1bmN0aW9uKGRmLCB2YXIsIHllYXIsIHR5cGUsIHRvcHNvaWwgPSBGQUxTRSwgc3Vic29pbCA9IEZBTFNFKSB7CiAgYXRtIDwtIGlmZWxzZSh5ZWFyID09ICIyMDAxIiwgYXRtLmQxNC4yMDAxLCBhdG0uZDE0LjIwMTkpCiAgaWYgKHR5cGUgPT0gImluYyIpIHsKICAgIGRmIDwtIGRmW2RmJGQxNGMgPiAtMjAwLCBdCiAgICB5bGltIDwtIGMoLTY1LCAxNjUpCiAgfSBlbHNlIHsKICAgIGlmICh0b3Bzb2lsKSB7CiAgICAgIGRmIDwtIGRmW2RmJGx5cl9ib3QgPCAzMSwgXQogICAgICB5bGltIDwtIGMoLTEyMCwgMTY1KQogICAgICB9CiAgICBpZiAoc3Vic29pbCkgewogICAgICBkZiA8LSBkZltkZiRseXJfYm90ID4gMzEsIF0KICAgICAgeWxpbSA8LSBjKC0yNzAsIDY1KQogICAgfQogIH0KICBpZiAodmFyID09ICJQTSIpIHsKICAgIGRmICU+JQogICAgICBtdXRhdGUocG0gPSBmYWN0b3IoaWZlbHNlKFBNID09ICJHUiIsICJncmFuaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwgImJhc2FsdCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImdyYW5pdGUiLCAiYW5kZXNpdGUiLCAiYmFzYWx0IikpKSAlPiUKICAgICAgZ3JvdXBfYnkocG0sIGx5cl9ib3QpICU+JQogICAgICBnZ3Bsb3QoLiwgYWVzKHBtLCBkMTRjKSkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdG0sIGxpbmV0eXBlID0gImRvdHRlZCIsIGFscGhhID0gMC4zKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgICAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvciA9IHBtKSwgbHdkID0gMSkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gIm5vbmUiKSArCiAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSB5bGltKSArCiAgICAgIGZhY2V0X2dyaWQoY29scyA9IHZhcnMobHlyX2JvdCkpICsKICAgICAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICAgICAgZ2d0aXRsZShwYXN0ZSh5ZWFyLCB0eXBlKSkgKwogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpKQogIH0gZWxzZSB7CiAgICBkZiAlPiUKICAgICAgbXV0YXRlKGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpKSAlPiUKICAgICAgZ3JvdXBfYnkoZWNvLCBseXJfYm90KSAlPiUKICAgICAgZ2dwbG90KC4sIGFlcyhlY28sIGQxNGMpKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGF0bSwgbGluZXR5cGUgPSAiZG90dGVkIiwgYWxwaGEgPSAwLjMpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogICAgICBnZW9tX2JveHBsb3QoYWVzKGNvbG9yID0gZWNvKSwgbHdkID0gMSkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygid2FybSIgPSB3YXJtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSBjb29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSBjb2xkKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gIm5vbmUiKSArCiAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSB5bGltKSArCiAgICAgIGZhY2V0X2dyaWQoY29scyA9IHZhcnMobHlyX2JvdCkpICsKICAgICAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICAgICAgZ2d0aXRsZShwYXN0ZSh5ZWFyLCB0eXBlKSkgKwogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpKQogIH0KfQoKIyBidWxrCmJveHBsb3QuZngoc3JhLjIwMDEuYnVsay5kZiwgIlBNIiwgIjIwMDEiLCAiYnVsayIsIHRvcHNvaWwgPSBUUlVFKQpib3hwbG90LmZ4KHNyYS4yMDE5LmJ1bGsuZGYsICJQTSIsICIyMDE5IiwgImJ1bGsiLCB0b3Bzb2lsID0gVFJVRSkKYm94cGxvdC5meChzcmEuMjAwMS5idWxrLmRmLCAiRUNPIiwgIjIwMDEiLCAiYnVsayIsIHRvcHNvaWwgPSBUUlVFKQpib3hwbG90LmZ4KHNyYS4yMDE5LmJ1bGsuZGYsICJFQ08iLCAiMjAxOSIsICJidWxrIiwgdG9wc29pbCA9IFRSVUUpCmJveHBsb3QuZngoc3JhLjIwMTkuYnVsay5kZiwgIkVDTyIsICIyMDE5IiwgImJ1bGsiLCBzdWJzb2lsID0gVFJVRSkKIyBpbmMKYm94cGxvdC5meChzcmEuMjAwMS5pbmMuZGYyLCAiUE0iLCAiMjAwMSIsICJpbmMiKQpib3hwbG90LmZ4KHNyYS4yMDE5LmluYy5kZjIsICJQTSIsICIyMDE5IiwgImluYyIpCmJveHBsb3QuZngoc3JhLjIwMDEuaW5jLmRmMiwgIkVDTyIsICIyMDAxIiwgImluYyIpCmJveHBsb3QuZngoc3JhLjIwMTkuaW5jLmRmMiwgIkVDTyIsICIyMDE5IiwgImluYyIpCmBgYAoKYGBge3IgZGVsdGEtZGVsdGEtcGxvdHN9CiMgZGF0YSwgdW5zdW1tYXJpemVkCnNyYS50cy5hbGwucmF3IDwtIHJiaW5kKAogIHNyYS4yMDAxLmJ1bGsuZGZbICwgbmFtZXMoc3JhLjIwMDEuYnVsay5kZikgJWluJSBuYW1lcyhzcmEuMjAwMS5pbmMuZGYyKV0sCiAgc3JhLjIwMTkuYnVsay5kZlsgLCBuYW1lcyhzcmEuMjAxOS5idWxrLmRmKSAlaW4lIG5hbWVzKHNyYS4yMDAxLmluYy5kZjIpXSwKICBzcmEuMjAwMS5pbmMuZGYyLAogIHNyYS4yMDE5LmluYy5kZjJbICwgbmFtZXMoc3JhLjIwMTkuaW5jLmRmMikgJWluJSBuYW1lcyhzcmEuMjAwMS5pbmMuZGYyKV0pICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIHBtID0gZmFjdG9yKGlmZWxzZShQTSA9PSAiR1IiLCAiZ3Jhbml0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsICJiYXNhbHQiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJncmFuaXRlIiwgImFuZGVzaXRlIiwgImJhc2FsdCIpKSwKICAgICAgICAgVHlwZSA9IGMocmVwKCJidWxrIiwgbGVuZ3RoID0gbnJvdyhzcmEuMjAwMS5idWxrLmRmKSksCiAgICAgICAgICAgICAgICAgIHJlcCgiYnVsayIsIGxlbmd0aCA9IG5yb3coc3JhLjIwMTkuYnVsay5kZikpLAogICAgICAgICAgICAgICAgICByZXAoImluYyIsIGxlbmd0aCA9IG5yb3coc3JhLjIwMDEuaW5jLmRmMikpLAogICAgICAgICAgICAgICAgICByZXAoImluYyIsIGxlbmd0aCA9IG5yb3coc3JhLjIwMTkuaW5jLmRmMikpKSwKICAgICAgICAgeWVhciA9IGMocmVwKDIwMDEsIGxlbmd0aCA9IG5yb3coc3JhLjIwMDEuYnVsay5kZikpLAogICAgICAgICAgICAgICAgICByZXAoMjAxOSwgbGVuZ3RoID0gbnJvdyhzcmEuMjAxOS5idWxrLmRmKSksCiAgICAgICAgICAgICAgICAgIHJlcCgyMDAxLCBsZW5ndGggPSBucm93KHNyYS4yMDAxLmluYy5kZjIpKSwKICAgICAgICAgICAgICAgICAgcmVwKDIwMTksIGxlbmd0aCA9IG5yb3coc3JhLjIwMTkuaW5jLmRmMikpKSkKCiMgcGxvdCBmeAp0cy5ncm91cFBsb3QuZnggPC0gZnVuY3Rpb24oZGYsIHgsIHkpIHsKICBxdW9feCA8LSBzeW0oeCkKICBxdW9feSA8LSBzeW0oeSkKICBpZiAoeCA9PSAicG0iKSB7CiAgICB2YXIubmFtZSA8LSAiUGFyZW50IG1hdGVyaWFsIgogICAgdmFyLnZhbHVlcyA8LSBjKCJhbmRlc2l0ZSIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSAKICB9IGVsc2UgewogICAgdmFyLm5hbWUgPC0gIkNsaW1hdGUiCiAgICB2YXIudmFsdWVzIDwtICBjKCJ3YXJtIiA9IHdhcm0sCiAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IGNvb2wsCiAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IGNvbGQpCiAgfQogIHBsb3QuZGYgPC0gZGYgJT4lCiAgICBmaWx0ZXIoZDE0YyA+IC0yMDApICU+JQogICAgZmlsdGVyKGx5cl9ib3QgPCAzMSkgJT4lCiAgICBncm91cF9ieSghISBxdW9feCwgbHlyX2JvdCwgVHlwZSwgeWVhcikgJT4lCiAgICBzdW1tYXJpemUoYWNyb3NzKGQxNGMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSkKICBpZiAoeSA9PSAiZGQxNGMiKSB7CiAgICBwbG90LmRmIDwtIHBsb3QuZGYgJT4lCiAgICAgIG11dGF0ZShhdG0gPSBpZmVsc2UoeWVhciA9PSAyMDAxLCBhdG0uZDE0LjIwMDEsIGF0bS5kMTQuMjAxOSksCiAgICAgICAgICAgICBkZDE0YyA9IGQxNGNfbWVhbiAtIGF0bSwKICAgICAgICAgICAgIHUgPSBkMTRjX21lYW4gKyBkMTRjX3NkIC0gYXRtLAogICAgICAgICAgICAgbCA9IGQxNGNfbWVhbiAtIGQxNGNfc2QgLSBhdG0pCiAgICBhdG0uZGYgPC0gYXRtLjE0YwogICAgYXRtLmRmJGQxNGMgPC0gMAogICAgeWxhYiA8LSBleHByZXNzaW9uKERlbHRhKkRlbHRhKicnXjE0KidDICjigLApJykgCiAgICB9IGVsc2UgewogICAgICBwbG90LmRmIDwtIHBsb3QuZGYgJT4lCiAgICAgICAgbXV0YXRlKHUgPSBkMTRjX21lYW4gKyBkMTRjX3NkLAogICAgICAgICAgICAgICBsID0gZDE0Y19tZWFuIC0gZDE0Y19zZCkKICAgICAgYXRtLmRmIDwtIGF0bS4xNGMKICAgICAgeWxhYiA8LSBleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykgCiAgICB9CiAgICBnZ3Bsb3QocGxvdC5kZiwgYWVzKHllYXIsICEhIHF1b195KSkgKwogICAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uZGYsIGFlcyh5ZWFyLCBkMTRjKSkgKwogICAgZ2VvbV9wYXRoKGFlcyhjb2xvciA9ICEhIHF1b194LCBsaW5ldHlwZSA9IFR5cGUpLCBhbHBoYSA9IC41LCBsd2QgPSAxKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9ICEhIHF1b194KSwgCiAgICAgICAgICAgICAgIHNpemUgPSAzLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpICsKICAgIGdlb21fZXJyb3JiYXIoCiAgICAgIGFlcyh5bWluID0gbCwKICAgICAgICAgIHltYXggPSB1LAogICAgICAgICAgY29sb3IgPSAhISBxdW9feCwKICAgICAgICAgIGFscGhhID0gVHlwZSksCiAgICAgIHdpZHRoID0gMSwKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9IHZhci5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZhci52YWx1ZXMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiwrFTRCIsCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB2YXIudmFsdWVzKSArCiAgICBzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzID0gYygiYnVsayIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImluYyIgPSAuNSkpICsKICAgIGZhY2V0X2dyaWQoY29scyA9IHZhcnMobHlyX2JvdCkpICsKICAgIHlsYWIoeWxhYikgKwogICAgeGxhYigiWWVhciIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKfQojIHBsb3QKdHMuZ3JvdXBQbG90LmZ4KHNyYS50cy5hbGwucmF3LCAicG0iLCAiZGQxNGMiKQp0cy5ncm91cFBsb3QuZngoc3JhLnRzLmFsbC5yYXcsICJlY28iLCAiZGQxNGMiKQp0cy5ncm91cFBsb3QuZngoc3JhLnRzLmFsbC5yYXcsICJwbSIsICJkMTRjX21lYW4iKQp0cy5ncm91cFBsb3QuZngoc3JhLnRzLmFsbC5yYXcsICJlY28iLCAiZDE0Y19tZWFuIikKYGBgCiMjIEluaXRpYWwgbW9kZWxpbmcKClRoZSBnb2FsIG9mIHRoaXMgbW9kZWxpbmcgZXhlcmNpc2UgaXMgdG8gc2VlIGhvdyBwYXJlbnQgbWF0ZXJpYWwgYW5kIGNsaW1hdGUvZWNvc3lzdGVtIGFmZmVjdCBlc3RpbWF0ZXMgb2Ygc29pbCBjYXJib24gYWdlcyBhbmQgdHJhbnNpdCB0aW1lcy4gQnVsayBzb2lsIF4xNF5DIG9ic2VydmF0aW9ucyBmcm9tIDIwMDEsIDIwMDksIGFuZCAyMDE5IHdpbGwgYmUgdXNlZCB0byBjb25zdHJhaW4gdGhlIGNhcmJvbiBtb2RlbHMsIGFzIHdlbGwgYXMgb2JzZXJ2YXRpb25zIG9mIF4xNF5DLUNPfjJ+IGZyb20gbGFib3JhdG9yeSBzb2lsIGluY3ViYXRpb25zIG9mIHNvaWxzIGNvbGxlY3RlZCBpbiAyMDAxIGFuZCAyMDE5LiBQcmV2aW91cyB3b3JrIGhhcyBpbmRpY2F0ZWQgdGhhdCB0aGUgY2FyYm9uIHN0b2NrcyBhdCB0aGVzZSBzaXRlcyBpcyBsaWtlbHkgYXQgZXF1aWxpYnJpdW0sIHNvIHdlIHdpbGwgYXBwbHkgdGhlIHN0ZWFkeS1zdGF0ZSBhc3N1bXB0aW9uIHRvIHRoZSBtb2RlbGluZy4KCiMjIyBUd28tcG9vbCBtb2RlbHMKCk9uZSBwb29sIG1vZGVscyBoYXZlIGJlZW4gc2hvd24gcmVwZWF0ZWRseSB0byBiZSBpbmFkZXF1YXRlIGZvciBkZXNjcmliaW5nIHNvaWwgY2FyYm9uIGR5bmFtaWNzLiBIb3dldmVyLCBhcyBzaW1wbGUgbW9kZWxzIGFyZSBlYXNpZXIgdG8gY29uc3RyYWluLCB3ZSB3aWxsIHN0YXJ0IHdpdGggYSB0d28tcG9vbCBwYXJhbGxlbCBhbmQgdHdvLXNlcmllcyBtb2RlbHMsIGFzIHRoZXNlIGFyZSB0aGUgc2ltcGxlc3QgbW9kZWwgc3lzdGVtIGJleW9uZCB0aGUgc2luZ2xlIHBvb2wgYXBwcm9hY2guIAoKVGhlIHR3by1wb29sIHBhcmFsbGVsIG1vZGVsIHJlcXVpcmVzIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoKKiBkZWNvbXBvc2l0aW9uIGNvbnN0YW50cyBmb3IgZWFjaCBwb29sICgqayp+MX4sICprKn4yfikKKiBpbnB1dCBwYXJ0aXRpb25pbmcgY29lZmZpY2llbnQgKCRcZ2FtbWEkKQoqIHN0ZWFkeS1zdGF0ZSBjYXJib24gc3RvY2tzIChDKQoqIGlucHV0cyAoSSkKKiBpbml0aWFsIHZhbHVlcyBvZiBeMTReQwoxClRoZSB0d28tcG9vbCBzZXJpZXMgbW9kZWwgcmVxdWlyZXMgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzOgoqIGRlY29tcG9zaXRpb24gY29uc3RhbnRzIGZvciBlYWNoIHBvb2wgKCprKn4xfiwgKmsqfjJ+KQoqIHRyYW5zZmVyIGNvZWZmaWNpZW50ICgkXGFscGhhJCkKKiBzdGVhZHktc3RhdGUgY2FyYm9uIHN0b2NrcyAoQykKKiBpbnB1dHMgKEkpCiogaW5pdGlhbCB2YWx1ZXMgb2YgXjE0XkMKCkRlY29tcG9zaXRpb24gcmF0ZXMgKCprKikgYXJlIHJlbGF0ZWQgdG8gdGhlIGFtb3VudCBvZiBeMTReQyBpbiBhIHByZS1ib21iIHN5c3RlbSAoZnJhY3Rpb24gbW9kZXJuLCAqRiopIGF0IHN0ZWFkeS1zdGF0ZSBieSB0aGUgZm9sbG93aW5nIGVxdWF0aW9ucyAoY2YuIFNjaHV1ciwgRHJ1ZmZsZSwgYW5kIFRydW1ib3JlLCAyMDE2KToKPioqRXEuIDEqKgoKJCRGID0gXGZyYWN7a317ayArIFxsYW1iZGF9JCQKPioqRXEuIDIqKgoKJCRrID0gXGZyYWN7XGxhbWJkYSBcY2RvdCBGfXsxIC0gRn0kJAo+d2hlcmUgJFxsYW1iZGEkIGlzIHRoZSByYWRpb2FjdGl2ZSBkZWNheSBjb25zdGFudCAoMS84MjY3KS4KCkFzIHRoZSBkZWNvbXBvc2l0aW9uIHJhdGVzIHdpbGwgdmFyeSwgdGhlIGluaXRpYWwgXjE0XkMgY29udGVudCBjYW4gYmUgZGV0ZXJtaW5lZCBkeW5hbWljYWxseSB3aXRoIGVxdWF0aW9uIDEuCgpDYXJib24gc3RvY2tzIGFyZSBrbm93biwgd2hpbGUgaW5wdXRzIHdpbGwgYmUgZXN0aW1hdGVkIGFuZCBhcmUgcmVsYXRlZCB0byB0aGUgc3RlYWR5LXN0YXRlIGNvbmRpdGlvbnMgYnkgdGhlIGZvbGxvd2luZyBlcXVhdGlvbjogCj4qKkVxLiAzKioKCiQkSSA9IChrX3sxfSBcY2RvdCBDX3sxfSkgKyAoa197Mn0gXGNkb3QgQ197Mn0pJCQKPndoZXJlICpDfjF+KiBhbmQgKkN+Mn4qIGFyZSB0aGUgY2FyYm9uIHN0b2NrcyBvZiB0aGUgdHdvIG1vZGVsIHBvb2xzLgoKQm90aCBzdG9ja3MgYW5kIGlucHV0cyBjYW4gYmUgc2NhbGVkIHRvIHRoZSBrbm93biB2YWx1ZSBvZiB0aGUgdG90YWwgY2FyYm9uIHBvb2wgb25jZSB0aGUgc3RlYWR5LXN0YXRlIHBhcmFtZXRlcnMgKCprfjF+KiwgKmt+Mn4qLCBhbmQgJFxnYW1tYSQgb3IgJFxhbHBoYSQpIGhhdmUgYmVlbiBkZXRlcm1pbmVkLiBQb29sIHNpemVzIGFyZSBhIGZ1bmN0aW9uIG9mIHRoZSBpbnB1dHMgYW5kIGlucHV0IHBhcnRpdGlvbmluZyBjb2VmZmljaWVudCBhdCBzdGVhZHktc3RhdGUuCgpBIE1vbnRlLUNhcmxvIE1hcmtvdiBjaGFpbiBhcHByb2FjaCB3aWxsIGJlIHVzZWQgZm9yIHBhcmFtZXRlciBlc3RpbWF0aW9uIGluIGNvbWJpbmF0aW9uIHdpdGggYW4gaW5pdGlhbCBvcHRpbWl6YXRpb24gYWxnb3JpdGhtIHRvIGRldGVybWluZSB0aGUgYmVzdCBzZXQgb2YgaW5pdGlhbCBwYXJhbWV0ZXJzLgoKIyMgV29ya2Zsb3cKCkluaXRpYWwgbW9kZWwgZml0dGluZyB3YXMgcGVyZm9ybWVkIGZvciBib3RoIG1vZGVsIHN0cnVjdHVyZXMgdXNpbmcgZ2VuZXJvdXMgcGFyYW1ldGVyIHJhbmdlcyBbMCwgMV0gZm9yIGFsbCB0aHJlZSBwYXJhbWV0ZXJzICgqa34xfiosICprfjJ+KiwgJFxnYW1tYSQgb3IgJFxhbHBoYSQpLiBUaGUgaW5pdGlhbCBwYXJhbWV0ZXIgc2V0IHdhcyBmb3VuZCBieSBmaXR0aW5nIHRoZSBtb2RlbHMgYnkgZXllLCBmb2xsb3dlZCBieSBvcHRpbWl6YXRpb24gd2l0aCB0aGUgZnVuY3Rpb24gIm1vZEZpdCIgKFIgcGFja2FnZSBGTUUpLCB1c2luZyB0aGUgTmVsZGVyLU1lYWQgYWxnb3JpdGhtLiBUaGUgYmVzdCBzZXQgb2YgcGFyYW1ldGVycyBmb3VuZCBieSBtb2RGaXQgd2FzIHRoZW4gdXNlZCBhcyB0aGUgaW5wdXQgdG8gYSBNb250ZSBDYXJsbyBNYXJrb3YgQ2hhaW4gKE1DTUMpLCB1c2luZyB0aGUgZnVuY3Rpb24gIm1vZE1DTUMiIChSIHBhY2thZ2UgRk1FKS4gVGhlIG51bWJlciBvZiBpdGVyYXRpb25zIGZvciB0aGUgTUNNQyBvcHRpbWl6YXRpb24gd2FzIHNldCBhdCA1MDAwIGludGlhbGx5LCB3aXRoIGRlbGF5ZWQgcmVqZWN0aW9uIGVtcGxveWVkIHRvIGluY3JlYXNlIGVmZmljaWVuY3kuIAoKVGhlIHN1bSBvZiB0aGUgbWVhbiBzcXVhcmVkIGVycm9yIGZvciB0aGUgYmVzdCBwYXJhbWV0ZXIgc2V0IHdhcyBzbGlnaHRseSBsb3dlciBmb3IgdGhlIHBhcmFsbGVsIHN0cnVjdHVyZSB0aGFuIGZvciB0aGUgc2VyaWVzIHN0cnVjdHVyZS4gQWRkaXRpb25hbGx5LCB0aGUgb3ZlcmFsbCBtZWFuIGVycm9yIG9mIHRoZSByZXNpZHVhbHMgd2FzIGFsc28gbG93ZXIgZm9yIHRoZSBwYXJhbGxlbCBzdHJ1Y3R1cmUsIG1vZGVyYXRlbHkgc28gZm9yIHRoZSBidWxrIEMgb2JzZXJ2YXRpb25zIGJ1dCBzdWJzdGFudGlhbGx5IHNvIGZvciB0aGUgcmVzcGlyYXRpb24gb2JzZXJ2YXRpb25zIChpbiBhbmRlc2l0ZSBhbmQgZ3Jhbml0ZSBzb2lscyBpbiBwYXJ0aWN1bGFyKS4KCkhvd2V2ZXIsIHRoZXNlIGluaXRpYWwgZml0cyB5aWVsZGVkIHVucmVhbGlzdGljIHBhcmFtZXRlciBlc3RpbWF0ZXMgZm9yIG11bHRpcGxlIHNpdGVzLCBwYXJ0aWN1bGFybHkgYXQgdGhlIGxvd2VyIGRlcHRocy4gQWRkaXRpb25hbGx5LCB0aGUgbW9kRml0IG91dHB1dCBzaG93ZWQgdmVyeSBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHBhcmFtZXRlcnMgZm9yIGJvdGggbW9kZWwgc3RydWN0dXJlcyAoc2xpZ2h0bHkgaGlnaGVyIGZvciB0aGUgdHdvLXBvb2wgc2VyaWVzIG1vZGVsKS4gCgpgYGB7ciBtb2QtdXRpbHN9CiMgayBmcm9tIGZyYWN0aW9uIG1vZGVybgprIDwtIGZ1bmN0aW9uIChGbSkgewogIChGbSAqIGxhbWJkYSkvKDEgLSBGbSkKfQoKIyBkMTRDIGZyb20gZnJhY3Rpb24gbW9kZXJuIApmbV8xNGMgPC0gZnVuY3Rpb24gKGZtLCBkYXRlKSB7CiAgKGZtICogZXhwKGxhbWJkYSAqICgxOTUwIC0gZGF0ZSkpIC0gMSkgKiAxMDAwCn0KCiMgcHJlLWJvbWIgZnJhY3Rpb24gbW9kZXJuIGZyb20gayAoc3RlYWR5LXN0YXRlIGFzc3VtZWQpCmZtIDwtIGZ1bmN0aW9uIChrKXsKICBrLyhrICsgbGFtYmRhKQp9CmBgYAoKYGBge3IgbW9kLWNvbnN0cmFpbnRzLCBpbmNsdWRlID0gRkFMU0V9CiMgSW5kaWNlcyBmb3IgZWFjaCBkZXB0aCBpbmNyZW1lbnQKaXguMTAgPC0gc2VxKDEsIDI3LCAzKQppeC4yMCA8LSBzZXEoMiwgMjcsIDMpCml4LjMwIDwtIHNlcSgzLCAyNywgMykKCiMjIFNPQyBzdG9ja3MKIyB1c2UgMjAxOSBTT0Mgc3RvY2tzIGZvciBzdGVhZHktc3RhdGUgZXN0aW1hdGVzCmNzb2MuMTkuMF8zMC5kZiA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNyYS4yMDE5LnNwLmxzLCBmdW5jdGlvbihkZikgewogICAgZGYgPC0gc3VwcHJlc3NNZXNzYWdlcygKICAgICAgZGYgJT4lCiAgICAgICAgZmlsdGVyKGx5cl9ib3QgPCAzMSAmIGx5cl9ib3QgPiAwKSAlPiUKICAgICAgICBzZWxlY3QoUE1lY28sIGx5cl90b3AsIGx5cl9ib3QsIGx5cl9zb2MpICU+JQogICAgICAgIGdyb3VwX2J5KFBNZWNvLCBseXJfdG9wLCBseXJfYm90KSkKICAgIHJldHVybihkYXRhLmZyYW1lKGRmKSkKICB9KQopCiMgY29udmVydCB0byAyNyBlbGVtZW50IGxpc3QKY3NvYy4xOS4wXzMwLmxzIDwtIHNwbGl0KGNzb2MuMTkuMF8zMC5kZiwgcGFzdGUwKGNzb2MuMTkuMF8zMC5kZiRQTWVjbywgIl8iLCBjc29jLjE5LjBfMzAuZGYkbHlyX3RvcCwgIi0iLCBjc29jLjE5LjBfMzAuZGYkbHlyX2JvdCkpCgojIGF2ZXJhZ2UKY3NvYy4xOS4wXzMwIDwtIGxhcHBseShjc29jLjE5LjBfMzAubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGF0YS5mcmFtZSgKICAgIGRmICU+JQogICAgICBncm91cF9ieShQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkgJT4lCiAgICAgIHN1bW1hcml6ZShseXJfc29jID0gbWVhbihseXJfc29jKSkpCn0pCgojIG1ha2UgaW50byBvYnMgZGF0YSBmcmFtZSBmb3IgbW9kLmNvc3QgZngKb2JzLmNTdG9jayA8LSBsYXBwbHkoY3NvYy4xOS4wXzMwLmxzLCBmdW5jdGlvbihkZikgewogIHJldHVybihkYXRhLmZyYW1lKHRpbWUgPSByZXAoYygyMDAxLjUsIDIwMDkuNSwgMjAxOS41KSwgZWFjaCA9IDMpLCBjU3RvY2sgPSByZXAoZGYkbHlyX3NvYywgMykpKQp9KQoKIyMgSW5wdXRzCiMgaW5pdGlhbCBpbnB1dHMgd2lsbCBiZSBzZXQgYXQgNCUgb2YgdGhlIGxheWVyIGNhcmJvbiBzdG9ja3MgKGFyYml0cmFyeSkKaW4uaSA8LSBsYXBwbHkoY3NvYy4xOS4wXzMwLCBmdW5jdGlvbih4KSAuMDQgKiB4JGx5cl9zb2MpCiMgSW5wdXRzIHdpbGwgYmUgYWRqdXN0ZWQgYmFzZWQgb24gdGhlIGZpdHRlZCBwYXJhbWV0ZXJzIHRvIG1hdGNoIG1lYXN1cmVkIHN0b2NrcyBsYXRlcgoKIyMgMTRDIGNvbnN0cmFpbnRzCiMgYnVsawpvYnMuYnVsay4xNGMgPC0gdW5saXN0KAogIGxhcHBseShzZXFfYWxvbmcoc3JhLjE5LjAxLnJlcC5scyksIGZ1bmN0aW9uKGkpIHsKICAjIGluZGV4IGFsb25nIGRlcHRoIGludGVydmFscyAwLTEwLCAxMC0yMCwgMjAtMzAKICBkZXB0aC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKDE6MyksIGZ1bmN0aW9uKGopIHsKICAgIGModW5saXN0KGxhcHBseShzcmEuMTkuMDEucmVwLmxzW1tpXV0sICJbWyIsIGopKSwKICAgICAgc3BsaXQoc3BsaXQoc3JhLjE5LjAxLjA5LCBzcmEuMTkuMDEuMDkkUE1lY28pW1tpXV0sCiAgICAgICAgICAgIHNwbGl0KHNyYS4xOS4wMS4wOSwgc3JhLjE5LjAxLjA5JFBNZWNvKVtbaV1dWyJseXJfYm90Il0pW1tqXV1bICwgImZtIl1bMl0sCiAgICAgIHVubGlzdChzcGxpdChzcmEuMjAxOS5sc1tbaV1dLCBzcmEuMjAxOS5sc1tbaV1dWyJseXJfYm90Il0pW1tqXV1bImZtIl0pKQogIH0pCiAgcmVwczAxIDwtIGxlbmd0aChzcmEuMTkuMDEucmVwLmxzW1tpXV0pCiAgZGVwdGguZGZzIDwtIGxhcHBseShkZXB0aC5scywgZnVuY3Rpb24oZm0pIHsKICAgIGRhdGEuZnJhbWUodGltZSA9IGMocmVwKDIwMDEuNSwgcmVwczAxKSwgMjAwOS41LCByZXAoMjAxOS41LCAzKSksCiAgICAgICAgICAgICAgIGJ1bGtDID0gRGVsdGExNENfZnJvbV9BYnNvbHV0ZUZyYWN0aW9uTW9kZXJuKGZtKSkKICB9KQogIHJldHVybihkZXB0aC5kZnMpCn0pLCByZWN1cnNpdmUgPSBGQUxTRSkKbmFtZXMob2JzLmJ1bGsuMTRjKSA8LSBwYXN0ZTAocmVwKGMoIkFOIiwgIkJTIiwgIkdSIiksIGVhY2ggPSA5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGMoInBwIiwgInJmIiwgIndmIiksIGVhY2ggPSAzLCB0aW1lcyA9IDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoYygiXzAtMTAiLCAiXzEwLTIwIiwgIl8yMC0zMCIpLCB0aW1lcyA9IDkpKQojIHJlc3BpcmF0aW9uCnNyYS4xOS4wMS5pbmMubWluLm1heCA8LSB1bmxpc3QoCiAgbGFwcGx5KHNlcV9hbG9uZygxOjMpLCBmdW5jdGlvbihpKSB7CiAgICBsYXBwbHkoCiAgICAgIG1hcHBseShtZXJnZSwKICAgICAgICAgICAgIGxhcHBseShsYXBwbHkoc3JhLjE5LjAxLmluYy5scywgIltbIiwgMiksICJbWyIsIGkpLCAKICAgICAgICAgICAgIGxhcHBseShsYXBwbHkoc3JhLjE5LjAxLmluYy5scywgIltbIiwgMyksICJbWyIsIGkpLAogICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSksCiAgICAgIGZ1bmN0aW9uKGRmKSB7CiAgICAgICAgZGF0YS5mcmFtZSh0aW1lID0gMjAwMS41LCByZXNwID0gYyhkZiR4LCBkZiR5KSkKICAgICAgfSkKICB9KSwgcmVjdXJzaXZlID0gRkFMU0UpCm5hbWVzKHNyYS4xOS4wMS5pbmMubWluLm1heCkgPC0gcGFzdGUwKG5hbWVzKHNyYS4xOS4wMS5pbmMubWluLm1heCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoYygiXzAtMTAiLCAiXzEwLTIwIiwgIl8yMC0zMCIpLCBlYWNoID0gOSkpCnNyYS4xOS4wMS5pbmMubWluLm1heCA8LSBsYXBwbHkoc3JhLjE5LjAxLmluYy5taW4ubWF4LCBmdW5jdGlvbihkZikgewogIGRmJHJlc3AgPC0gY2FsY18xNGMoZGYkcmVzcCwgMjAwMSkKICByZXR1cm4oZGYpCn0pCgpzcmEuMjAxOS5pbmMubWluLm1heCA8LSB1bmxpc3QobGFwcGx5KHNyYS4yMDE5LmluYy5scywgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgICB4JHJlc3AgPC0geCRkMTRjCiAgICB4JHRpbWUgPC0geCRZZWFyICsgLjUKICAgIHJldHVybih4WyAsIGMoInRpbWUiLCAicmVzcCIpXSkKICB9KQp9KSwgcmVjdXJzaXZlID0gRkFMU0UpCm5hbWVzKHNyYS4yMDE5LmluYy5taW4ubWF4KSA8LSBnc3ViKCJcXC4iLCAiXyIsIG5hbWVzKHNyYS4yMDE5LmluYy5taW4ubWF4KSkKZm9yIChpIGluIHNlcV9hbG9uZyhuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heCkpKSB7CiAgbmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpW2ldIDwtIGlmZWxzZShncmVwbCgiMTAiLCBuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heClbaV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdzdWIoIjEwIiwgIjAtMTAiLCBuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heClbaV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiMjAiLCBuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heClbaV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnc3ViKCIyMCIsICIxMC0yMCIsIG5hbWVzKHNyYS4yMDE5LmluYy5taW4ubWF4KVtpXSksIGdzdWIoIjMwIiwgIjIwLTMwIiwgbmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpW2ldKSkpCn0KCm9icy5yZXNwLjE0YyA8LSByYmluZChiaW5kX3Jvd3Moc3JhLjE5LjAxLmluYy5taW4ubWF4LCAuaWQgPSAiaWQiKSwKICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyhzcmEuMjAxOS5pbmMubWluLm1heCwgLmlkID0gImlkIikpCm9icy5yZXNwLjE0YyA8LSBsYXBwbHkoc3BsaXQob2JzLnJlc3AuMTRjLCBvYnMucmVzcC4xNGMkaWQpLCBmdW5jdGlvbihkZikgZGZbICwgMjozXSkKCiMjIGlucHV0L3N0b2NrIHJhdGlvCnJhczA2IDwtIGRhdGEuZnJhbWUocmVhZF9leGNlbCgiLi4vZGF0YS9leHRlcm5hbC9zcmFfcmFzX2luYy9SZXNwUmF0ZXNfUmFzbXVzc2VuMjAwNi54bHN4Iiwgc2hlZXQgPSAiUmF0ZXNTdW0iKSkKIyBPYnMgY29zdApvYnMuZmx4LnN0b2NrIDwtIGxhcHBseShzcGxpdChyYXMwNiwgcmFzMDYkUE1lY28pLCBmdW5jdGlvbih4KSB7CiAgZGF0YS5mcmFtZSh0aW1lID0gMjAwMS41LCAjIGFyYml0cmFyeQogICAgICAgICAgICAgZmx4LnN0b2NrID0geFsgLCAiZmx4X3N0b2NrX3JhdGlvIl0pCn0pCgojIGNhbGN1bGF0ZSBpbnB1dHMgdXNpbmcgZmx4L3N0b2NrIHJhdGlvCmluLmZseC5zdG9jayA8LSBsYXBwbHkoc2VxX2Fsb25nKG9icy5mbHguc3RvY2spLCBmdW5jdGlvbihpKSB7CiAgb2JzLmZseC5zdG9ja1tbaV1dW1siZmx4LnN0b2NrIl1dL2Nzb2MuMTkuMF8zMFtpeC4xMF1bW2ldXVtbImx5cl9zb2MiXV0KfSkKCiMgRmx1eCBlc3RpbWF0ZWQgZnJvbSBHb3VsZGVuIGV0IGFsLiAyMDEyOyBUYW5nIGV0IGFsLiAyMDA1OyBXYW5nIGV0IGFsLiAyMDAwOyBHYXVkaW5za2kgMjAwMAojIGZsdXhlcyBieSBlbGV2YXRpb24gZnJvbSBHUFAgcmVwb3J0ZWQgaW4gR291bGRlbiBldCBhbC4gRmlnLiA1IGFuZCBhcHByb3hpbWF0ZWQKIyBSaCBwZXJjZW50YWdlIGZyb20gVGFuZyBldCBhbC4gMjAwNSA9IDAuNDQgKGFubi4gbWVhbiBCbG9kZ2V0dCk7IGNmLiAwLjQ4IEhhcnZhcmQgRm9yZXN0CiMgQSBob3Jpem9uIGVzdC4gMC41NSBmcm9tIEdhdWRpbnNraQojIGFzc3VtaW5nIEEgPSAwLTMwLCBhc3N1bWUgMC0xMCA9IDUwJSwgMTAtMjAgPSAzMCUsIDIwLTMwID0gMjAlIG9mIHRvdGFsIEEgcHJvZHVjdGlvbiAKaHpuQS5SaC5rZ20yIDwtIDAuNDQgKiAwLjU1ICogMTBeLTMKZ3BwLmxzIDwtIGMoMTgwMCwgMTYwMCwgMTQwMCkKaW4uZnJjLmxzIDwtIGMoMC41LCAwLjMsIDAuMikKCiMgZnggZm9yIGNhbGN1bGF0aW5nIGlucHV0cwppbi5mbHguZnggPC0gZnVuY3Rpb24oUE1lY29fZGVwdGgpIHsKICBncHAgPC0gaWZlbHNlKGdyZXBsKCJwcCIsIFBNZWNvX2RlcHRoKSwgZ3BwLmxzWzFdLCBpZmVsc2UoZ3JlcGwoIndmIiwgUE1lY29fZGVwdGgpLCBncHAubHNbMl0sIGdwcC5sc1szXSkpCiAgaW4uZnJjIDwtIGlmZWxzZShncmVwbCgiMC0xMCIsIFBNZWNvX2RlcHRoKSwgaW4uZnJjLmxzWzFdLCBpZmVsc2UoZ3JlcGwoIjEwLTIwIiwgUE1lY29fZGVwdGgpLCBpbi5mcmMubHNbMl0sIGluLmZyYy5sc1szXSkpCiAgcmV0dXJuKGdwcCAqIGluLmZyYyAqIGh6bkEuUmgua2dtMikKfQoKIyBpbnB1dCBsaXN0CmluLmVzdCA8LSBsYXBwbHkoc2VxX2Fsb25nKG9icy5jU3RvY2spLCBmdW5jdGlvbihpKSB7CiAgUE1lY29fZGVwdGggPC0gbmFtZXMob2JzLmNTdG9jaylbaV0KICByZXR1cm4oaW4uZmx4LmZ4KFBNZWNvX2RlcHRoKSkKfSkKbmFtZXMoaW4uZXN0KSA8LSBuYW1lcyhvYnMuY1N0b2NrKQpgYGAKCmBgYHtyIG1vZC1mdW5zLWdlbn0KIyBpbmRleCBvZiB5ZWFycyBmb3Igd2hpY2ggYnVsay9yZXNwIDE0QyBhcmUga25vd24KeWVhci5peCA8LSBjKHdoaWNoKERhdG0kRGF0ZSA9PSAyMDAxLjUpLAogICAgICAgICAgICAgd2hpY2goRGF0bSREYXRlID09IDIwMDkuNSksCiAgICAgICAgICAgICB3aGljaChEYXRtJERhdGUgPT0gMjAxOS41KSkKCiMgZnVuY3Rpb24gZm9yIHNhdmluZyBjb25zdHJhaW50IGRhdGEgaW4gYSBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nIGluIGdncGxvdCcKY29uLmRmLmZ4IDwtIGZ1bmN0aW9uKFBNZWNvX2RlcHRoKSB7CiAgYnVsay5kZiA8LSBvYnMuYnVsay4xNGNbW1BNZWNvX2RlcHRoXV0KICByZXNwLmRmIDwtIG9icy5yZXNwLjE0Y1tbUE1lY29fZGVwdGhdXQogIHJldHVybigKICAgIGNvbi5kZiA8LSBkYXRhLmZyYW1lKHBvb2wgPSBjKHJlcCgiYnVsayBDIiwgbnJvdyhidWxrLmRmKSksIHJlcCgicmVzcGlyYXRpb24iLCBucm93KHJlc3AuZGYpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBkMTRjID0gYyhidWxrLmRmJGJ1bGtDLCByZXNwLmRmJHJlc3ApLAogICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9IGMoYnVsay5kZiR0aW1lLCByZXNwLmRmJHRpbWUpKSkKfQoKIyBwbG90IGZ1bmN0aW9uCkMxNC4ycC5wbG90LmZ4IDwtIGZ1bmN0aW9uKHBsb3QuZGYsIGNvbi5kZiwgbW9kLCBQTWVjb19kZXB0aCkgewogIHBsb3QuZGYgJT4lCiAgZmlsdGVyKHBvb2wgPT0gImJ1bGsgQyIgfCBwb29sID09ICJyZXNwaXJhdGlvbiIgfCBwb29sID09ICJhdG0iKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHllYXJzLCBkMTRDLCBjb2xvciA9IHBvb2wpKSArCiAgZ2VvbV9wYXRoKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGNvbi5kZiwgYWVzKFllYXIsIGQxNGMsIGNvbG9yID0gcG9vbCksIHNpemUgPSAzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgbmFtZSA9ICJQb29sIiwKICAgIHZhbHVlcyA9IGMoImF0bSIgPSA4LAogICAgICAgICAgICAgICAiYnVsayBDIiA9ICJibGFjayIsCiAgICAgICAgICAgICAgICJmYXN0IiA9ICIjRDgxQjYwIiwKICAgICAgICAgICAgICAgInNsb3ciID0gIiMxRTg4RTUiLAogICAgICAgICAgICAgICAicmVzcGlyYXRpb24iID0gIiNGRkMxMDciKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5NTAsIDIwMjIpKSArCiAgZ2d0aXRsZShwYXN0ZShQTWVjb19kZXB0aCwgbW9kKSkgKwogIHhsYWIoIlllYXIiKSArCiAgeWxhYihleHByZXNzaW9uKCcnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQp9CkMxNC4xcC5wbG90LmZ4IDwtIGZ1bmN0aW9uKHBsb3QuZGYsIGNvbi5kZiwgbW9kLCBQTWVjb19kZXB0aCkgewogIGdncGxvdChwbG90LmRmLCBhZXMoeWVhcnMsIGQxNEMsIGNvbG9yID0gcG9vbCkpICsKICBnZW9tX3BhdGgoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gY29uLmRmLCBhZXMoWWVhciwgZDE0YywgY29sb3IgPSBwb29sKSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gIlBvb2wiLAogICAgdmFsdWVzID0gYygiYXRtIiA9IDgsCiAgICAgICAgICAgICAgICJidWxrIEMiID0gImJsYWNrIiwKICAgICAgICAgICAgICAgInJlc3BpcmF0aW9uIiA9ICIjRkZDMTA3IikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxOTUwLCAyMDIyKSkgKwogIGdndGl0bGUocGFzdGUoUE1lY29fZGVwdGgsICIgMXAgYnVsayArIDFwIHJlc3AiKSkgKwogIHhsYWIoIlllYXIiKSArCiAgeWxhYihleHByZXNzaW9uKCcnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQp9CgojIHNldCB1cCBtb2RlbCBmdW5jdGlvbiBmb3Igb3B0aW1pemF0aW9uCiMgTk9URTogcGFyWzNdIGZvciAycHMgbW9kZWwgY2hhbmdlZCB0byBwcm9wb3J0aW9uIHRyYW5zZmVycmVkIChubyBsb25nZXIgPSBhMjEpCiMgdGhlcmVmb3JlLCBhMjEgPSBwYXJbM10gKiBwYXJbMV0KbW9kRnVuXzJwIDwtIGZ1bmN0aW9uKHBhcnMsIEluLCBsYWcgPSAwLCBwYXNzID0gVFJVRSwgb3V0ID0gIm1vZEZpdCIsIG1vZCkgewogCiAgIyBpbnRpYWwgMTRDCiAgRjBfRGVsdGExNEMgPC0gdW5saXN0KGxhcHBseShwYXJzWzE6Ml0sIGZ1bmN0aW9uKHgpIERlbHRhMTRDX2Zyb21fQWJzb2x1dGVGcmFjdGlvbk1vZGVybihmbSh4KSkpKQogIAogICMgbW9kZWwgbWF0cml4CiAgQSA8LSAtZGlhZyhwYXJzWzE6Ml0pCiAgaWYgKG1vZCA9PSAiMnBzIikgewogICAgYTIxIDwtIHBhcnNbM10gKiBwYXJzWzFdCiAgICBBWzIsIDFdIDwtIGEyMQogIH0KICAgIAogICMgc3RlYWR5LXN0YXRlIEMgc3RvY2tzCiAgaWYgKG1vZCA9PSAiMnBwIikgewogICAgc3MuY3N0b2NrIDwtICgtMSAqIHNvbHZlKEEpICUqJSBjKEluICogcGFyc1szXSwgSW4gKiAoMSAtIHBhcnNbM10pKSkKICB9IGVsc2UgewogICAgc3MuY3N0b2NrIDwtICgtMSAqIHNvbHZlKEEpICUqJSBjKEluLCAwKSkKICB9CiAgCiAgIyB0aW1lIGluZGV4CiAgaXgudCA8LSBjKChsYWcgKyAxKTpucm93KERhdG0pKQogIAogICMgbW9kZWwKICBpZiAobW9kID09ICIycHAiKSB7CiAgICBtb2QgPC0gVHdvcFBhcmFsbGVsTW9kZWwxNCh0ID0gRGF0bSREYXRlW2l4LnRdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3MgPSBwYXJzWzE6Ml0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDMCA9IGMoc3MuY3N0b2NrWzFdLCBzcy5jc3RvY2tbMl0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRjBfRGVsdGExNEMgPSBGMF9EZWx0YTE0QywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gSW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnYW0gPSBwYXJzWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRGYyA9IERhdG0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWcgPSBsYWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXNzID0gcGFzcykKICB9IGVsc2UgewogICAgbW9kIDwtIFR3b3BTZXJpZXNNb2RlbDE0KHQgPSBEYXRtJERhdGVbaXgudF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3MgPSBwYXJzWzE6Ml0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQzAgPSBjKHNzLmNzdG9ja1sxXSwgc3MuY3N0b2NrWzJdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGMF9EZWx0YTE0QyA9IEYwX0RlbHRhMTRDLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gSW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYTIxID0gYTIxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0RmMgPSBEYXRtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhZyA9IGxhZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXNzID0gcGFzcykKICB9CiAgCiAgIyBnZXQgbW9kIHZhbHVlcwogIEMxNG0gPC0gZ2V0RjE0Qyhtb2QpCiAgQzE0cCA8LSBnZXRGMTQobW9kKQogIEMxNHIgPC0gZ2V0RjE0Uihtb2QpCiAgQ3RvdCA8LSBnZXRDKG1vZCkKICAKICBpZihvdXQgPT0gIm1vZEZpdCIpIHsKICAgICMgZGF0YWZyYW1lIGZvciBtb2RGaXQgZngKICAgIHJldHVybihkYXRhLmZyYW1lKAogICAgICB0aW1lID0gRGF0bSREYXRlW2l4LnRdLAogICAgICBidWxrQyA9IEMxNG0sIAogICAgICByZXNwID0gQzE0ciwKICAgICAgY1N0b2NrID0gcm93U3VtcyhDdG90KSkpCiAgfSBlbHNlIHsKICAgICMgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKICAgIHJldHVybihkYXRhLmZyYW1lKAogICAgICB5ZWFycyA9IHJlcChEYXRtJERhdGVbaXgudF0sIDUpLAogICAgICBkMTRDID0gYyhDMTRwWywxXSwgCiAgICAgICAgICAgICAgIEMxNHBbLDJdLCAKICAgICAgICAgICAgICAgQzE0bSwKICAgICAgICAgICAgICAgQzE0ciwKICAgICAgICAgICAgICAgRGF0bSROSGMxNFtpeC50XSksCiAgICAgIHBvb2wgPSByZXAoYygiZmFzdCIsICJzbG93IiwgImJ1bGsgQyIsICJyZXNwaXJhdGlvbiIsICJhdG0iKSwgZWFjaCA9IG5yb3coQzE0cCkpKSkKICB9Cn0KCiMgMXAgbW9kRnVuCm1vZEZ1bl8xcCA8LSBmdW5jdGlvbihwYXJzLCBJbiwgbGFnID0gMCwgb3V0ID0gIm1vZEZpdCIsIG1vZCwgcGFzcyA9IFRSVUUpIHsKIAogICMgaW50aWFsIDE0QwogIEYwX0RlbHRhMTRDIDwtIERlbHRhMTRDX2Zyb21fQWJzb2x1dGVGcmFjdGlvbk1vZGVybihmbShwYXJzKSkKICAKICAjIHN0ZWFkeS1zdGF0ZSBDIHN0b2NrcwogIHNzLmNzdG9jayA8LSBJbi9wYXJzCiAgCiAgIyB0aW1lIGluZGV4CiAgaXgudCA8LSBjKChsYWcgKyAxKTpucm93KERhdG0pKQogIAogICMgbW9kZWwKICBtb2QgPC0gc3VwcHJlc3NXYXJuaW5ncygKICAgICMgd2FybmluZ3Mgc3VwcHJlc3NlZCBkdWUgdG8gdGhlICJGYyIgd2FybmluZwogICAgT25lcE1vZGVsMTQodCA9IERhdG0kRGF0ZVtpeC50XSwKICAgICAgICAgICAgICAgICAgICAgayA9IHBhcnMsCiAgICAgICAgICAgICAgICAgICAgIEMwID0gc3MuY3N0b2NrLAogICAgICAgICAgICAgICAgICAgICBGMF9EZWx0YTE0QyA9IEYwX0RlbHRhMTRDLAogICAgICAgICAgICAgICAgICAgICBJbiA9IEluLAogICAgICAgICAgICAgICAgICAgICBpbnB1dEZjID0gRGF0bSwKICAgICAgICAgICAgICAgICAgICAgbGFnID0gbGFnLAogICAgICAgICAgICAgICAgICAgICBwYXNzID0gcGFzcykKICApCiAgCiAgIyBnZXQgbW9kIHZhbHVlcwogIEMxNG0gPC0gZ2V0RjE0Qyhtb2QpCiAgQ3RvdCA8LSBnZXRDKG1vZCkKICAKICBpZihvdXQgPT0gIm1vZEZpdCIpIHsKICAgICMgZGF0YWZyYW1lIGZvciBtb2RGaXQgZngKICAgIHJldHVybihkYXRhLmZyYW1lKAogICAgICB0aW1lID0gRGF0bSREYXRlW2l4LnRdLAogICAgICBidWxrQyA9IEMxNG0sCiAgICAgIGNTdG9jayA9IEN0b3QpKQogIH0gZWxzZSB7CiAgICAjIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCiAgICByZXR1cm4oZGF0YS5mcmFtZSgKICAgICAgeWVhcnMgPSByZXAoRGF0bSREYXRlW2l4LnRdLCAxKSwKICAgICAgZDE0QyA9IGMoQzE0bSwKICAgICAgICAgICAgICAgRGF0bSROSGMxNFtpeC50XSksCiAgICAgIHBvb2wgPSByZXAoYygiYnVsayBDIiwgImF0bSIpLCBlYWNoID0gbGVuZ3RoKEMxNG0pKSkpCiAgfQp9CgojIGZ1bmN0aW9uIGZvciB0cmlhbCBhbmQgZXJyb3IgYXBwcm9hY2ggdG8gZmluZGluZyBpbml0aWFsIHBhcmFtZXRlciBzZXQKcGFyLmZ4IDwtIGZ1bmN0aW9uKHBhcnMsIEluLCBsYWcgPSAwLCBvdXQgPSAicGxvdC5kZiIsIHZlcmJvc2UgPSBUUlVFLCBtb2QsIHBhc3MgPSBGQUxTRSkgewogIAogICMgbW9kZWwgbWF0cml4CiAgQSA8LSAtZGlhZyhwYXJzWzE6Ml0pCiAgaWYgKG1vZCA9PSAiMnBzIikgewogICAgYTIxIDwtIHBhcnNbM10gKiBwYXJzWzFdCiAgICBBWzIsIDFdIDwtIGEyMQogICAgIyBzdGVhZHktc3RhdGUgc3RvY2tzCiAgICBzcy5jc3RvY2sgPC0gcm91bmQoKC0xICogc29sdmUoQSkgJSolIGMoSW4sIDApKSwgMSkKICB9IGVsc2UgaWYgKG1vZCA9PSAiMnBwIikgewogICAgIyBzdGVhZHktc3RhdGUgc3RvY2tzCiAgICBzcy5jc3RvY2sgPC0gcm91bmQoKC0xICogc29sdmUoQSkgJSolIGMoSW4gKiBwYXJzWzNdLCBJbiAqICgxIC0gcGFyc1szXSkpKSwgMSkKICB9IGVsc2UgewogICAgc3MuY3N0b2NrIDwtIEluL3BhcnMKICB9CiAgCiAgY3N0b2NrLnN1bSA8LSBpZmVsc2UobGVuZ3RoKHNzLmNzdG9jaykgPT0gMSwgc3MuY3N0b2NrLCBjb2xTdW1zKHNzLmNzdG9jaykpCiAgCiAgIyBwcmludCBzaXRlIGFuZCBzdGVhZHktc3RhdGUgc3RvY2tzCiAgaWYgKHZlcmJvc2UpIHsKICAgIGNhdChwYXN0ZTAoUE1lY29fZGVwdGgsICJcbiIpKQogICAgaWYgKG1vZCA9PSAiMnBzIiB8IG1vZCA9PSAiMnBwIikgewogICAgICBjYXQocGFzdGUwKHNzLmNzdG9ja1sxXSwgIiAoZmFzdCBwb29sKVxuIiwgc3MuY3N0b2NrWzJdLCAiIChzbG93IHBvb2wpXG4iKSkKICAgICAgY2F0KHBhc3RlMCgic2xvdyBwb29sOiAiLCByb3VuZChzcy5jc3RvY2tbMl0gLyBjc3RvY2suc3VtICogMTAwLCAwKSwgIiVcbiIpKSAKICAgIH0KICAgIGNhdChyb3VuZChjc3RvY2suc3VtLCAxKSwgIiAobW9kZWxlZCBzdG9ja3MpXG4iKQogICAgY2F0KHJvdW5kKGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCAibHlyX3NvYyJdLCAxKSwgIiAobWVhc3VyZWQgc3RvY2tzKVxuIikgCiAgfQogIGlmIChtb2QgPT0gIjFwIikgewogICAgcmV0dXJuKG1vZEZ1bl8xcChwYXJzID0gcGFycywgSW4gPSBJbiwgbGFnID0gbGFnLCBvdXQgPSBvdXQsIG1vZCA9ICIxcCIsIHBhc3MgPSBwYXNzKSkKICB9CiAgaWYgKG1vZCA9PSAiMnBwIikgewogICByZXR1cm4obW9kRnVuXzJwKHBhcnMgPSBwYXJzLCBJbiA9IEluLCBsYWcgPSBsYWcsIG91dCA9IG91dCwgbW9kID0gIjJwcCIsIHBhc3MgPSBwYXNzKSkgCiAgfSBlbHNlIGlmIChtb2QgPT0gIjJwcyIpIHsKICAgIHJldHVybihtb2RGdW5fMnAocGFycyA9IHBhcnMsIEluID0gSW4sIGxhZyA9IGxhZywgb3V0ID0gb3V0LCBtb2QgPSAiMnBzIiwgcGFzcyA9IHBhc3MpKSAKICB9Cn0KYGBgCgpgYGB7ciBpbnB1dHMtc3RvY2tzfQojIyBhZGp1c3QgaW5wdXRzIHRvIG1hdGNoIHN0b2NrcwojIGZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBzdGVhZHktc3RhdGUgU09DIHN0b2Nrcwpzb2MuZnggPC0gZnVuY3Rpb24obW9kU3RyLCBwYXJzLCBJbiwgb3V0ID0gInBvb2xzIikgewogIGlmIChtb2RTdHIgPT0gIjJwcCIpIHsKICAgIGNtYXQgPC0gLTEgKiBzb2x2ZSgtZGlhZyhwYXJzWzE6Ml0pKSAlKiUgYyhJbiAqIHBhcnNbM10sIEluICogKDEgLSBwYXJzWzNdKSkKICB9IGVsc2UgewogICAgQSA8LSAtZGlhZyhwYXJzWzE6Ml0pCiAgICBBWzIsIDFdIDwtIHBhcnNbM10gIyBub3RlIHRoYXQgYTIxIGRlZmluZWQgYXMgcGN0IHRyYW5zZmVyICogazEKICAgIGNtYXQgPC0gLTEgKiBzb2x2ZShBKSAlKiUgYyhJbiwgMCkgIyBJbiBpcyB0b3RhbCBpbnB1dCBpbnRvIHRoZSBzeXN0ZW0KICB9CiAgaWYgKG91dCA9PSAicG9vbHMiKSB7CiAgICByZXR1cm4oY21hdCkKICB9IGVsc2UgewogICAgcmV0dXJuKGNvbFN1bXMoY21hdCkpCiAgfQp9Cgppbi5maXQuZnggPC0gZnVuY3Rpb24obW9kU3RyLCBwYXJzLCBpbml0aWFsSW4sIFNPQykgewogICMgc2VxdWVuY2Ugb2YgcG9zc2libGUgaW5wdXQgdmFsdWVzCiAgaWYgIChTT0MgPCBzb2MuZngobW9kU3RyLCBwYXJzLCBpbml0aWFsSW4sIG91dCA9ICJzdW0iKSkgewogICAgaW5zIDwtIHNlcSguMDEsIAogICAgICAgICAgICAgICBpbml0aWFsSW4sIAogICAgICAgICAgICAgICAuMDEpCiAgICB9IGVsc2UgewogICAgICBpbnMgPC0gc2VxKGluaXRpYWxJbiwgCiAgICAgICAgICAgICAgICAgU09DLCAKICAgICAgICAgICAgICAgICAuMDEpCiAgICB9CiAgIyBtb2RlbGVkIHN0b2NrcwogIHNvY19tb2QgPC0gbGFwcGx5KHNlcV9hbG9uZyhpbnMpLCBmdW5jdGlvbihqKSB7CiAgICBzb2MuZngobW9kU3RyLCBwYXJzLCBpbnNbal0sIG91dCA9ICJzdW0iKQogIH0pCiAgaXggPC0gd2hpY2gubWluKGFicyh1bmxpc3Qoc29jX21vZCkgLSBTT0MpKQogIHJldHVybihpbnNbaXhdKQp9CgojIGxvYWQgaW5pdGlhbCBwYXJhbWV0ZXIgc2V0CmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9wYXJzLmkuMnBwXzIwMjEtMDMtMzAuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvcGFycy5pLjJwc18yMDIwLTExLTE2LlJkYXRhIikKCiMjIGlucHV0cyBmb3IgaW5pdGlhbCBwYXIgc2V0IGFuZCBtZWFzdXJlZCBzdG9ja3MKIyAycHAKaW4ubWVhcy4ycHAgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmkuMnBwW2l4LjEwXSksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmkuMnBwW2l4LjEwXSlbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcCIsIHBhcnMuaS4ycHBbaXguMTBdW1tpXV0sIGluLmlbaXguMTBdW1tpXV0sIFNPQykpCn0pCm5hbWVzKGluLm1lYXMuMnBwKSA8LSBuYW1lcyhwYXJzLmkuMnBwW2l4LjEwXSkKIyAycHMKaW4ubWVhcy4ycHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmkuMnBzW2l4LjEwXSksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmkuMnBzW2l4LjEwXSlbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcCIsIHBhcnMuaS4ycHNbaXguMTBdW1tpXV0sIGluLmlbaXguMTBdW1tpXV0sIFNPQykpCn0pCm5hbWVzKGluLm1lYXMuMnBzKSA8LSBuYW1lcyhwYXJzLmkuMnBzW2l4LjEwXSkKCiMgRmx1eCBlc3RpbWF0ZWQgZnJvbSBHb3VsZGVuIGV0IGFsLiAyMDEyOyBUYW5nIGV0IGFsLiAyMDA1OyBXYW5nIGV0IGFsLiAyMDAwOyBHYXVkaW5za2kgMjAwMAojIGZsdXhlcyBieSBlbGV2YXRpb24gZnJvbSBHUFAgcmVwb3J0ZWQgaW4gR291bGRlbiBldCBhbC4gRmlnLiA1IGFuZCBhcHByb3hpbWF0ZWQKIyBSaCBwZXJjZW50YWdlIGZyb20gVGFuZyBldCBhbC4gMjAwNSA9IDAuNDQgKGFubi4gbWVhbiBCbG9kZ2V0dCk7IGNmLiAwLjQ4IEhhcnZhcmQgRm9yZXN0CiMgQSBob3Jpem9uIGVzdC4gMC41NSBmcm9tIEdhdWRpbnNraQojIGFzc3VtaW5nIEEgPSAwLTMwLCBhc3N1bWUgMC0xMCA9IDUwJSwgMTAtMjAgPSAzMCUsIDIwLTMwID0gMjAlIG9mIHRvdGFsIEEgcHJvZHVjdGlvbiAKaHpuQS5SaC5rZ20yIDwtIDAuNDQgKiAwLjU1ICogMTBeLTMKZ3BwLmxzIDwtIGMoMTgwMCwgMTYwMCwgMTQwMCkKaW4uZnJjLmxzIDwtIGMoMC41LCAwLjMsIDAuMikKCiMgZnggZm9yIGNhbGN1bGF0aW5nIGlucHV0cwppbi5mbHguZnggPC0gZnVuY3Rpb24oUE1lY29fZGVwdGgpIHsKICBncHAgPC0gaWZlbHNlKGdyZXBsKCJwcCIsIFBNZWNvX2RlcHRoKSwgZ3BwLmxzWzFdLCBpZmVsc2UoZ3JlcGwoIndmIiwgUE1lY29fZGVwdGgpLCBncHAubHNbMl0sIGdwcC5sc1szXSkpCiAgaW4uZnJjIDwtIGlmZWxzZShncmVwbCgiMC0xMCIsIFBNZWNvX2RlcHRoKSwgaW4uZnJjLmxzWzFdLCBpZmVsc2UoZ3JlcGwoIjEwLTIwIiwgUE1lY29fZGVwdGgpLCBpbi5mcmMubHNbMl0sIGluLmZyYy5sc1szXSkpCiAgcmV0dXJuKGdwcCAqIGluLmZyYyAqIGh6bkEuUmgua2dtMikKfQoKIyBpbnB1dCBsaXN0CmluLmVzdCA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuaS4ycHApLCBmdW5jdGlvbihpKSB7CiAgUE1lY29fZGVwdGggPC0gbmFtZXMocGFycy5pLjJwcClbaV0KICByZXR1cm4oaW4uZmx4LmZ4KFBNZWNvX2RlcHRoKSkKfSkKbmFtZXMoaW4uZXN0KSA8LSBuYW1lcyhwYXJzLmkuMnBwKQpgYGAKIyMgUGFyYW1ldGVyIG9wdGltaXphdGlvbgoKT3B0aW1pemluZyB0aGUgcGFyYW1ldGVyIHNldCByZXF1aXJlcyBpbXBvc2luZyBjb3N0cyBhbmQgb3B0aW9uYWxseSBjb25zdHJhaW5pbmcgdGhlIGFsbG93YWJsZSByYW5nZSBvZiB2YWx1ZXMgZm9yIGVhY2ggcGFyYW1ldGVyLiBHaXZlbiB0aGF0IHdlIG9ubHkgaGF2ZSBkYXRhIGZvciB0aHJlZSB0aW1lIHBvaW50cywgdGhpcyBpcyBhIHJlbGF0aXZlbHkgc3BhcnNlIGRhdGEgc2V0IGZvciBjb25zdHJhaW5pbmcgdGhlc2UgbW9kZWxzLiBBY2NvcmRpbmdseSwgdGhlIG9wdGltaXphdGlvbiBwcm9jZWR1cmUgd2lsbCBiZW5lZml0IGZyb20gKmEgcHJpb3JpKiBjb25zdHJhaW50cyBvZiB0aGUgYWxsb3dhYmxlIHBhcmFtZXRlciByYW5nZXMuIEZvciBleGFtcGxlLCBzaW5jZSB3ZSBhc3N1bWUgdGhhdCB0aGUgc3lzdGVtIGNhbm5vdCBiZSBhZGVxdWF0ZWx5IG1vZGVsZWQgYXMgYSBzaW5nbGUgaG9tb2dlbm91cyByZXNlcnZvaXIsIHdlIHdpbGwgZW5zdXJlIHRoYXQgdGhlIG9wdGltaXphdGlvbiBwcm9jZWR1cmUgY2Fubm90IGNvbGxhcHNlIHRoZSB0d28tcG9vbCBzeXN0ZW0gaW50byBhIHNpbmdsZSBwb29sLiBUaGlzIGNhbiBiZSBtaXRpZ2F0ZWQgaW4gdGhlIHR3by1wb29sIHBhcmFsbGVsIG9wdGltaXphdGlvbiBieSBjb25zdHJhaW5pbmcgJFxnYW1tYSQgKGkuZS4gdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGlucHV0cyBlbnRlcmluZyB0aGUgZmFzdCBwb29sKSB0byBhIHJhbmdlIG9mIDUwJSB0byA5NSUuIFNpbWlsYXJseSwgZm9yIHRoZSB0d28tcG9vbCBzZXJpZXMgbW9kZWwgc3RydWN0dXJlIHdlIGNhbiBjb25zdHJhaW4gdGhlIHJhbmdlIG9mIHRoZSB0cmFuc2ZlciBjb2VmZmljaWVudCB0byBiZSBiZXR3ZWVuIDAuMCBhbmQgMC4xLCBlbnN1cmluZyB0aGF0IHNvbWUgY2FyYm9uIHJlbWFpbnMgaW4gdGhlIGZhc3QgY3ljbGluZyBwb29sLgoKQWRkaXRpb25hbGx5LCB0byBlbmZvcmNlIGEgcmVsYXRpdmVseSBmYXN0IGN5Y2xpbmcgcG9vbCBhbmQgcmVsYXRpdmVseSBzbG93ZXIgY3ljbGluZyBwb29sLCB3ZSB3aWxsIGxvb3NlbHkgY29uc3RyYWluIHRoZSBpbnRyaW5zaWMgZGVjb21wb3NpdGlvbiByYXRlcyBhcyB3ZWxsIChib3RoIG1vZGVsIHN0cnVjdHVyZXMpOgoKKmt+MX4qOiBbMC4wMiwgMS4wMF0gKDUwIHRvIDEgeWVhcikKKmt+Mn4qOiBbMC4wMDAxLCAwLjAyXSAoMTAsMDAwIHRvIDUwIHllYXJzKQoKRmluYWxseSwgdGhlIG1vZGVscyB3aWxsIGJlIHJ1biB0byBlbmZvcmNlIHN0ZWFkeS1zdGF0ZSwgaS5lLiB3aXRoIHVudmFyeWluZyBjYXJib24gc3RvY2tzLiBUaGUgYW1vdW50IG9mIGNhcmJvbiBvYnNlcnZlZCBpbiB0aGUgc3lzdGVtIHdpbGwgYmUgdXNlZCBpbiB0aGUgY29zdCBmdW5jdGlvbiBpbiBhZGRpdGlvbiB0byB0aGUgcmFkaW9jYXJib24gb2JzZXJ2YXRpb25zIG1hZGUgaW4gMjAwMSwgMjAwOSwgYW5kIDIwMTkuIFRoZSBpbnB1dHMgd2lsbCBiZSBlc3RpbWF0ZWQgZnJvbSBuZXQgZWNvc3lzdGVtIGV4Y2hhbmdlIChORUUpIGRhdGEgbWVhc3VyZWQgYXQgbmVhcmJ5IGVkZHkgY292YXJpYW5jZSBzaXRlczogQmxvZGdldHQgZXhwZXJpbWVudGFsIGZvcmVzdCAoQW1lcmlGbHV4KSwgTG93ZXIgVGVha2V0dGxlIChORU9OKSwgYW5kIFNvYXByb290IFNhZGRsZSAoTkVPTikuIEFsdGVybmF0aXZlbHksIHVzaW5nIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGZsdXhlcyBtZWFzdXJlZCBmcm9tIHRoZXNlIGVkZHkgY292YXJpYW5jZSB0b3dlcnMgYW5kIEdQUCBlc3RpbWF0ZWQgZnJvbSBzYXRlbGxpdGUgcmV0cmlldmFscyBvZiBTSUYsIGVzdGltYXRlcyBjYW4gYmUgbWFkZSBmb3IgaW5wdXRzIGF0IHRoZSBwaXhlbHMgY29ycmVzcG9uZGluZyB0byBlYWNoIHNpdGUgbG9jYXRpb24uCgpgYGB7ciBvcHQtbW9kLCBldmFsID0gRkFMU0V9CiMgTm90ZTogdGhpcyBvbmx5IHJ1bnMgaWYgZXZhbCBmbGFnIHN3aXRjaGVkIHRvIFRSVUUKIyMgT3B0aW1pemUgbW9kZWwgcGFycwojIENvc3QgZnVuY3Rpb24gKGV2YWx1YXRlcyBlcnJvciBhcyBtb2RlbCB2cy4gb2JzdiwgcGVyIEZNRSByZXEpCiMgbm90ZSB0aGF0IHdlIGhhdmUgdG8gc2V0ICJwYXNzIiB0byBUUlVFIHNvIFNvaWxSIG1vZGVsIGRvZXNuJ3QgZmFpbCAobmVnLiByZXNwKQptb2QuZml0cy5meCA8LSBmdW5jdGlvbihtb2QsIHBhcnMsIEluLCBzdWIsIGxhZyA9IDAsIHVwcGVyLCBsb3dlciwgY29zdCkgewogIAogICMgc3RhcnQgbG9vcAogIGxhcHBseShzZXFfYWxvbmcocGFyc1tzdWJdKSwgZnVuY3Rpb24oaSkgewogICAgCiAgICAjIHN0YXJ0IHRpbWVyIGFuZCBwcmludCBQTWVjb19kZXB0aAogICAgc3RhcnQgPC0gU3lzLnRpbWUoKQogICAgY2F0KHBhc3RlMChuYW1lcyhwYXJzKVtzdWJdW2ldLCAiIHBhcmFtZXRlciBmaXR0aW5nXG4iKSkKICAKICAgICMgZGVmaW5lIHBhcnMKICAgIHBhcnMgPC0gcGFyc1tzdWJdW1tpXV0KICAgIGlmIChtb2QgPT0gIjJwcCIpIHsKICAgICAgbmFtZXMocGFycykgPC0gYygiazEiLCAiazIiLCAiZ2FtIikKICAgIH0gZWxzZSB7CiAgICAgIG5hbWVzKHBhcnMpIDwtIGMoImsxIiwgImsyIiwgInRjIikKICAgIH0KICAgIAogICAgIyBTZXQgaW5wdXQKICAgIEluIDwtIEluW3N1Yl1bW2ldXQogICAgCiAgICAjIGRlZmluZSBjb3N0IGZ1bmN0aW9uCiAgICBpZiAoY29zdCA9PSAiMTRDICsgY1N0b2NrIikgewogICAgICBtb2QuQ29zdCA8LSBmdW5jdGlvbihwYXJzKSB7CiAgICAgICAgbW9kZWxPdXRwdXQgPC0gbW9kRnVuXzJwKHBhcnMsIEluLCBtb2QgPSBtb2QsIGxhZyA9IGxhZykKICAgICAgICBjb3N0MSA8LSBtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5idWxrLjE0Y1tzdWJdW1tpXV0sIHNjYWxlVmFyID0gVFJVRSkKICAgICAgICBjb3N0MiA8LSBtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5yZXNwLjE0Y1tzdWJdW1tpXV0sIHNjYWxlVmFyID0gVFJVRSwgY29zdCA9IGNvc3QxKSAKICAgICAgICByZXR1cm4obW9kQ29zdChtb2RlbCA9IG1vZGVsT3V0cHV0LCBvYnMgPSBvYnMuY1N0b2NrW3N1Yl1bW2ldXSwgY29zdCA9IGNvc3QyKSkKICAgICAgfQogICAgfSBlbHNlIGlmIChjb3N0ID09ICIxNEMgKyBzdG9jay9mbHgiKSB7CiAgICAgIG1vZC5Db3N0IDwtIGZ1bmN0aW9uKHBhcnMpIHsKICAgICAgICBtb2RlbE91dHB1dCA8LSBtb2RGdW5fMnAocGFycywgSW4sIG1vZCA9IG1vZCwgbGFnID0gbGFnKQogICAgICAgIGNvc3QxIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmJ1bGsuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFKQogICAgICAgIGNvc3QyIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLnJlc3AuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFLCBjb3N0ID0gY29zdDEpIAogICAgICAgIHJldHVybihtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5mbHguc3RvY2tbW2ldXSwgY29zdCA9IGNvc3QyKSkKICAgICAgfQogICAgfSBlbHNlIGlmIChjb3N0ID09ICIxNEMiKSB7CiAgICAgIG1vZC5Db3N0IDwtIGZ1bmN0aW9uKHBhcnMpIHsKICAgICAgICBtb2RlbE91dHB1dCA8LSBtb2RGdW5fMnAocGFycywgSW4sIG1vZCA9IG1vZCwgbGFnID0gbGFnKQogICAgICAgIGNvc3QxIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmJ1bGsuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFKQogICAgICAgIHJldHVybihtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5yZXNwLjE0Y1tzdWJdW1tpXV0sIHNjYWxlVmFyID0gVFJVRSwgY29zdCA9IGNvc3QxKSkKICAgICAgfSAKICAgIH0gZWxzZSBpZiAoY29zdCA9PSAiMTRDIGJ1bGsgKyBjU3RvY2siKSB7CiAgICAgIG1vZC5Db3N0IDwtIGZ1bmN0aW9uKHBhcnMpIHsKICAgICAgICBtb2RlbE91dHB1dCA8LSBtb2RGdW5fMnAocGFycywgSW4sIG1vZCA9IG1vZCwgbGFnID0gbGFnKQogICAgICAgIGNvc3QxIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmJ1bGsuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFKQogICAgICAgIHJldHVybihtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5jU3RvY2tbc3ViXVtbaV1dLCBjb3N0ID0gY29zdDEpKQogICAgICB9CiAgICB9IGVsc2UgaWYgKGNvc3QgPT0gIjE0QyBidWxrIG9ubHkiKSB7CiAgICAgIG1vZC5Db3N0IDwtIGZ1bmN0aW9uKHBhcnMpIHsKICAgICAgICBtb2RlbE91dHB1dCA8LSBtb2RGdW5fMnAocGFycywgSW4sIG1vZCA9IG1vZCwgbGFnID0gbGFnKQogICAgICAgIHJldHVybihtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5idWxrLjE0Y1tzdWJdW1tpXV0sIHNjYWxlVmFyID0gVFJVRSkpCiAgICAgIH0KICAgIH0KICAgIAogICAgIyBmaXQgcGFycwogICAgZml0IDwtIHRyeUNhdGNoKAogICAgICBtb2RGaXQoZiA9IG1vZC5Db3N0LAogICAgICAgICAgICAgcCA9IHBhcnMsCiAgICAgICAgICAgICBtZXRob2QgPSAnTmVsZGVyLU1lYWQnLAogICAgICAgICAgICAgdXBwZXIgPSB1cHBlciwgCiAgICAgICAgICAgICBsb3dlciA9IGxvd2VyKSwKICAgICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKICAgIAogICAgU2Z1biA8LSBzZW5zRnVuKG1vZC5Db3N0LCBmaXQkcGFyKQogICAgCiAgICAjIEVuZCB0aW1lciBhbmQgcHJpbnQgZWxhcHNlZCB0aW1lCiAgICBlbmQgPC0gU3lzLnRpbWUoKQogICAgY2F0KHBhc3RlMCgidGltZTogIiwgZW5kIC0gc3RhcnQsICJcbiIpKQogICAgCiAgICAjIFJldHVybiBmaXR0ZWQgcGFyYW1ldGVycyBhbmQgc2Vuc2l0aXZpdHkKICAgIHJldHVybihsaXN0KG1vZGZpdCA9IGZpdCwgCiAgICAgICAgICAgICAgICBzZW5zID0gU2Z1bikpCiAgfSkgCn0KCiMjIDJwcAojIHBhciByYW5nZSBbMCwgMV0gZm9yIGFsbCBwYXJzCm1vZC5zZW5zLmZpdHMuMnBwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgY29uc3RyYWluIGdhbW1hIHRvIFswLjUsIDAuOTVdCm1vZC5zZW5zLmZpdHMuMnBwLnAzLjUuOTUgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgMSwgMC45NTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMC41KSkKbmFtZXMobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHAucDMuNS45NSIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHAucDMuNS45NSA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSwgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyAycHAzIChwYXIgcmFuZ2UgY29uc3RyYWludHMsIGlucHV0cyBmaXQgdG8gbWVhcyBzdG9ja3MpCm1vZC5zZW5zLmZpdHMuMnBwMyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLm1lYXMuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk1MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgb25seSIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBwMykgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHAzLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcDMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBwMyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAzLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMnBwM3MgKHBhciByYW5nZSBjb25zdHJhaW50cywgaW5wdXRzIGZpdCB0byBtZWFzIHN0b2NrcywgKyBzdG9jayBjb25zdHJhaW50KQptb2Quc2Vucy5maXRzLjJwcDNzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4ubWVhcy4ycHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk1MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gImNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBwM3MpIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwM3MsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBwM3MiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBwM3MgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwM3MsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIDJwcwojIHBhciByYW5nZSBbMCwgMV0gZm9yIGFsbCBwYXJzCm1vZC5zZW5zLmZpdHMuMnBzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKDAsIDAsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcywgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcywgZnVuY3Rpb24oeCkgeFtbMV1dKQojIDIwLTMwCm1vZC5zZW5zLmZpdHMuMnBzLjMwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKDAsIDAsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcy4zMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMzAiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzLjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4zMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyAycHMzIChwYXIgcmFuZ2UgY29uc3RyYWludHMsIGlucHV0cyBmaXQgdG8gbWVhcyBzdG9ja3MpCm1vZC5zZW5zLmZpdHMuMnBzMyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLm1lYXMuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIDEsIC4xNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgLjAwMDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgb25seSIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzMykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMzLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwczMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzMyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMzLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMnBzMyAocGFyIHJhbmdlIGNvbnN0cmFpbnRzLCBpbnB1dHMgZml0IHRvIG1lYXMgc3RvY2tzLCArIHN0b2NrIGNvbnN0cmFpbnQpCm1vZC5zZW5zLmZpdHMuMnBzM3MgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5tZWFzLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMzcykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMzcywgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMzcyIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHMzcyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMzcywgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyMjIDJwNCAocGFyIHJhbmdlIHNldCwgc3RvY2sgYW5kIGJ1bGsgMTRDIGNvc3RzLCBHUFAtYmFzZWQgaW5wdXRzIGJ5IGVjbykKIyMgMnBwCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwcDQuMTAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTUxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBidWxrICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHA0LjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcDQuMTAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBwNC4xMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHA0LjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDQuMTAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAyMC0zMAptb2Quc2Vucy5maXRzLjJwcDQuMzAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTUxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBidWxrICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHA0LjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4zMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcDQuMzAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBwNC4zMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHA0LjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDQuMzAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyMgMnBzCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwczQuMTAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBidWxrICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHM0LjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczQuMTAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzNC4xMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHM0LjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczQuMTAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAyMC0zMAptb2Quc2Vucy5maXRzLjJwczQuMzAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBidWxrICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHM0LjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczQuMzAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzNC4zMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHM0LjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczQuMzAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIyAycDRyIChwYXIgcmFuZ2Ugc2V0LCBzdG9jaywgYnVsaywgYW5kIHJlc3BpcmF0aW9uIDE0QyBjb3N0cywgR1BQLWJhc2VkIGlucHV0cyBieSBlY28pCiMjIDJwcAojIDAtMTAKbW9kLnNlbnMuZml0cy4ycHA0ci4xMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTUxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHA0ci4xMCkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHA0ci4xMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHA0ci4xMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHA0ci4xMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHA0ci4xMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIDIwLTMwCm1vZC5zZW5zLmZpdHMuMnBwNHIuMzAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk1MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBwNHIuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjMwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwNHIuMzAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBwNHIuMzAiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBwNHIuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNHIuMzAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyMgMnBzCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwczRyLjEwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwczRyLjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczRyLjEwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwczRyLjEwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczRyLjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczRyLjEwLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMjAtMzAKbW9kLnNlbnMuZml0cy4ycHM0ci4zMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHM0ci4zMCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHM0ci4zMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHM0ci4zMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHM0ci4zMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHM0ci4zMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQpgYGAKCmBgYHtyIHJlcG9ydC1wYXItZml0fQojIGxvYWQgaW5pdGlhbCBwYXJhbWV0ZXJzIGFzIG5lZWRlZAppZiAoIWV4aXN0cygicGFycy5pLjJwcCIpKSB7CiBsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvcGFycy5pLjJwcF8yMDIwLTExLTE2LlJkYXRhIikgCn0KaWYgKCFleGlzdHMoInBhcnMuaS4ycHMiKSkgewogIGxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9wYXJzLmkuMnBzXzIwMjAtMTEtMTYuUmRhdGEiKSAgCn0KCiMgbG9hZCBmaXRzIGFzIG5lZWRlZAppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBwIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBwXzIwMjAtMTEtMTYuUkRhdGEiKQp9CmlmICghZXhpc3RzKCJtb2QuZml0cy4ycHAucDMuNS45NSIpKSB7CiAgbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcC5wMy41Ljk1XzIwMjAtMTEtMTYuUmRhdGEiKSAgCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwcyIpKSB7CiBsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwc18yMDIwLTExLTE2LlJkYXRhIikKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBwMiIpKSB7CiBsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcC5mbHguc3RvY2tfMjAyMC0xMi0wMi5SRGF0YSIpCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwczIiKSkgewogbG9hZChmaWxlID0gIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMuZmx4LnN0b2NrXzIwMjAtMTItMDIuUmRhdGEiKQp9CmlmICghZXhpc3RzKCJtb2QuZml0cy4ycHAzIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBwM18yMDIwLTEyLTA4LlJEYXRhIikKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBzMyIpKSB7CiBsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwczNfMjAyMC0xMi0wOC5SZGF0YSIpCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwcDNzIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBwM3NfMjAyMC0xMi0wOC5SRGF0YSIpCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwczNzIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzM3NfMjAyMC0xMi0wOC5SZGF0YSIpCn0KCiMjIFBhciBlc3RpbWF0ZXMKIyAycHAKcGFycy5maXQuMnBwIDwtIGxhcHBseShtb2QuZml0cy4ycHAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcCkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCiMgMnBwIGdhbSA9IFsuNSwgLjk1XQpwYXJzLmZpdC4ycHAucDMuNS45NSA8LSBsYXBwbHkobW9kLmZpdHMuMnBwLnAzLjUuOTUsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcC5wMy41Ljk1KSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KCiMgMnBzCnBhcnMuZml0LjJwcyA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQoKCiMgMnBwMiAoaW5wdXQvc3RvY2sgYW5kIDE0QyBjb25zdHJhaW50cykKcGFycy5maXQuMnBwMiA8LSBsYXBwbHkobW9kLmZpdHMuMnBwMiwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwMikgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCiMgMnBzMiAoaW5wdXQvc3RvY2sgYW5kIDE0QyBjb25zdHJhaW50cykKcGFycy5maXQuMnBzMiA8LSBsYXBwbHkobW9kLmZpdHMuMnBzMiwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzMikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCgojIDJwcDMgKDE0QyBjb25zdHJhaW50cywgY29uc3RyYWluZWQgcGFyIHJhbmdlcywgc3RvY2stZml0IGlucHV0cykKcGFycy5maXQuMnBwMyA8LSBsYXBwbHkobW9kLmZpdHMuMnBwMywgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwMykgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCiMgMnBzMyAoMTRDIGNvbnN0cmFpbnRzLCBjb25zdHJhaW5lZCBwYXIgcmFuZ2VzLCBzdG9jay1maXQgaW5wdXRzKQpwYXJzLmZpdC4ycHMzIDwtIGxhcHBseShtb2QuZml0cy4ycHMzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KCiMgMnBwM3MgKDE0QyBjb25zdHJhaW50cywgY29uc3RyYWluZWQgcGFyIHJhbmdlcywgc3RvY2stZml0IGlucHV0cywgKyBzdG9jayBjb25zdHJhaW50KQpwYXJzLmZpdC4ycHAzcyA8LSBsYXBwbHkobW9kLmZpdHMuMnBwM3MsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcDNzKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KIyAycHMzcyAoMTRDIGNvbnN0cmFpbnRzLCBjb25zdHJhaW5lZCBwYXIgcmFuZ2VzLCBzdG9jay1maXQgaW5wdXRzLCArIHN0b2NrIGNvbnN0cmFpbnQpCnBhcnMuZml0LjJwczNzIDwtIGxhcHBseShtb2QuZml0cy4ycHMzcywgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzM3MpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQoKIyMgc3RvY2sgJiBidWxrIDE0QyBjb3N0cyBvbmx5CiMgMnBwCnBhcnMuZml0LjJwcDQuMTAgPC0gbGFwcGx5KG1vZC5maXRzLjJwcDQuMTAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcDQuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpwYXJzLmZpdC4ycHA0LjMwIDwtIGxhcHBseShtb2QuZml0cy4ycHA0LjMwLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHA0LjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4zMF0KIyAycHMKcGFycy5maXQuMnBzNC4xMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBzNC4xMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzNC4xMCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnBhcnMuZml0LjJwczQuMzAgPC0gbGFwcGx5KG1vZC5maXRzLjJwczQuMzAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwczQuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQoKIyMgc3RvY2ssIGJ1bGsgYW5kIHJlc3BpcmF0aW9uIDE0QyBjb3N0cwojIDJwcApwYXJzLmZpdC4ycHA0ci4xMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBwNHIuMTAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcDRyLjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KcGFycy5maXQuMnBwNHIuMzAgPC0gbGFwcGx5KG1vZC5maXRzLjJwcDRyLjMwLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHA0ci4zMCkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMzBdCiMgMnBzCnBhcnMuZml0LjJwczRyLjEwIDwtIGxhcHBseShtb2QuZml0cy4ycHM0ci4xMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzNHIuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQpwYXJzLmZpdC4ycHM0ci4zMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBzNHIuMzAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwczRyLjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KCiMjIFN1bW1hcnkgb2YgZml0cwojIDJwcApwYXJzLmZpdC4ycHAuc3VtIDwtIGxhcHBseShtb2QuZml0cy4ycHAsIGZ1bmN0aW9uKHgpIHsKICB0cnlDYXRjaChzdW1tYXJ5KHgpLCAKICAgICAgICAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhwYXJzLmZpdC4ycHAuc3VtKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHApCiMgMnBzCnBhcnMuZml0LjJwcy5zdW0gPC0gbGFwcGx5KG1vZC5maXRzLjJwcywgZnVuY3Rpb24oeCkgewogIHRyeUNhdGNoKHN1bW1hcnkoeCksIAogICAgICAgICAgIGVycm9yID0gZnVuY3Rpb24gKGUpIHtjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKX0pCn0pCm5hbWVzKHBhcnMuZml0LjJwcy5zdW0pIDwtIG5hbWVzKHBhcnMuZml0LjJwcykKCiMjIFN1bW1hcnkgb2YgZXJyb3JzCiMgYmVzdCBwYXIgc2V0IChzc3IpCnNzci4ycHAuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwcCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHMsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKc3NyLjJwcDIuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwcDIsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKc3NyLjJwczIuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwczIsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKIyBzdG9jayBhbmQgYnVsayAxNEMgY29zdHMgb25seQpzc3IuMnBwNC4xMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwNC4xMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBwNC4zMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwNC4zMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzNC4xMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBzNC4xMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzNC4zMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBzNC4zMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQojIHN0b2NrLCBidWxrIGFuZCByZXNwIDE0QyBjb3N0cwpzc3IuMnBwNHIuMTAuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwcDRyLjEwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHA0ci4zMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwNHIuMzAsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKc3NyLjJwczRyLjEwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHM0ci4xMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzNHIuMzAuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwczRyLjMwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCgojIG1lYW4gcmVzaWR1YWxzLCBieSB2YXIgKHZhcl9tcykKdmFyX21zLmRmLmZ4IDwtIGZ1bmN0aW9uKG1vZC5maXRzLmxzLCBjb3N0cykgewogIGRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy5scywgIlsiLCAidmFyX21zIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQogIGlmIChsZW5ndGgoY29zdHMpID09IDIgKSB7CiAgICBkZiR2YXIgPC0gcmVwKGMoInJlc3AiLCAiYnVsa0MiKSwgbnJvdyhkZikvMikKICB9IGVsc2UgewogICAgZGYkdmFyIDwtIHJlcChjKCJyZXNwIiwgImJ1bGtDIiwgImZseC5zdG9jayIpLCBucm93KGRmKS8zKQogIH0KICBkZiR2YXJfbXMgPC0gcm91bmQoZGYkdmFyX21zLCA1KQogIHJldHVybihkZikKfQp2YXJfbXMuMnBwLmRmIDwtIHZhcl9tcy5kZi5meChtb2QuZml0cy4ycHAsIGMoInJlc3AiLCAiYnVsa0MiKSkKdmFyX21zLjJwcC5wMy41Ljk1LmRmIDwtIHZhcl9tcy5kZi5meChtb2QuZml0cy4ycHAucDMuNS45NSwgYygicmVzcCIsICJidWxrQyIpKQp2YXJfbXMuMnBzLmRmIDwtIHZhcl9tcy5kZi5meChtb2QuZml0cy4ycHMsIGMoInJlc3AiLCAiYnVsa0MiKSkKdmFyX21zLjJwcDIuZGYgPC0gdmFyX21zLmRmLmZ4KG1vZC5maXRzLjJwcDIsIGMoInJlc3AiLCAiYnVsa0MiLCAiZmx4LnN0b2NrIikpCnZhcl9tcy4ycHMyLmRmIDwtIHZhcl9tcy5kZi5meChtb2QuZml0cy4ycHMyLCBjKCJyZXNwIiwgImJ1bGtDIiwgImZseC5zdG9jayIpKQoKIyBiaW5kIGZpdHRlZCBwYXJzIHdpdGggaW5pdGlhbCBwYXJzIGludG8gZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcvc3VtbWFyaXppbmcKcGFyLmZpdC5kZi5meCA8LSBmdW5jdGlvbihtb2QsIHBhcnMuZml0LCBwYXJzLmkpIHsKICBkZiA8LSBiaW5kX3Jvd3MoCiAgICBsYXBwbHkoCiAgICAgIG1hcHBseShyYmluZCwgCiAgICAgICAgICAgICBwYXJzLmZpdCwKICAgICAgICAgICAgIHBhcnMuaSwKICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpLCAKICAgICAgZnVuY3Rpb24oZGYpIHsKICAgICAgICBkZiA8LSBkYXRhLmZyYW1lKGRmKQogICAgICAgIGlmIChtb2QgPT0gIjJwcCIpIHsKICAgICAgICAgIGNvbG5hbWVzKGRmKSA8LSBjKCJrZmFzdCIsICJrc2xvdyIsICJnYW0iKQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjb2xuYW1lcyhkZikgPC0gYygia2Zhc3QiLCAia3Nsb3ciLCAiYTIxIikKICAgICAgICB9CiAgICAgICAgZGYkZXN0IDwtIGMoImZpdCIsICJpbml0IikKICAgICAgICByZXR1cm4oZGYpCiAgICAgIH0pCiAgKQogIGRmJFBNZWNvX2RlcHRoIDwtIHJlcChuYW1lcyhwYXJzLmkpLCBlYWNoID0gMikKICBkZiRQTSA8LSBzdWJzdHIoZGYkUE1lY29fZGVwdGgsIHN0YXJ0ID0gMSwgc3RvcCA9IDIpCiAgZGYkZWNvIDwtIHN1YnN0cihkZiRQTWVjb19kZXB0aCwgc3RhcnQgPSAzLCBzdG9wID0gNCkKICBkZiRkZXB0aCA8LSBzdWJzdHIoZGYkUE1lY29fZGVwdGgsIHN0YXJ0ID0gNiwgc3RvcCA9IGxlbmd0aChkZiRQTWVjb19kZXB0aCkpCiAgcmV0dXJuKGRmKQp9CgoKIyMgMnBwCiMgZ2FtIHJhbmdlID0gWzAsIDFdCnBhcnMuZml0LjJwcC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwcFtpeC4xMF0pCiMgZ2FtIHJhbmdlID0gWy41LCAuOTVdCnBhcnMuZml0LjJwcC5wMy41Ljk1LmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHAucDMuNS45NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjEwXSkKIyB3LyBpbnB1dC9zdG9jayBjb3N0IGFuZCBnYW0gcmFuZ2UgPSBbLjUsIC45NV0KcGFycy5maXQuMnBwMi5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwcFtpeC4xMF0pCgojIyAycHMKIyBhMjEgcmFuZ2UgPSBbMCwgMV0KcGFycy5maXQuMnBzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyB3LyBpbnB1dC9zdG9jayBjb3N0IGFuZCBhMjEgcmFuZ2UgPSBbMCwgMV0KcGFycy5maXQuMnBzMi5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwczIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQoKIyMgQ29uc3RyYWluZWQgcGFyIHJhbmdlcywgd2l0aCBhbmQgd2l0aG91dCBzdG9jayBjb25zdHJhaW50CiMgdy9vIHN0b2NrCnBhcnMuZml0LjJwcDMuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHBbaXguMTBdKQpwYXJzLmZpdC4ycHMzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwczMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyB3LyBzdG9jawpwYXJzLmZpdC4ycHAzcy5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwM3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4xMF0pCnBhcnMuZml0LjJwczNzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMzcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyB3LyBzdG9jayAmIGJ1bGsgMTRDIG9ubHkKcGFycy5maXQuMnBwNC4xMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHA0LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwcFtpeC4xMF0pCnBhcnMuZml0LjJwcDQuMzAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwNC4zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHBbaXguMzBdKQpwYXJzLmZpdC4ycHM0LjEwLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwczQuMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKcGFycy5maXQuMnBzNC4zMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHM0LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4zMF0pCgojIHcvIHN0b2NrLCBidWxrICsgcmVzcCAxNEMKcGFycy5maXQuMnBwNHIuMTAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwNHIuMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjEwXSkKcGFycy5maXQuMnBwNHIuMzAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwNHIuMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjMwXSkKcGFycy5maXQuMnBzNHIuMTAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzNHIuMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKcGFycy5maXQuMnBzNHIuMzAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzNHIuMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjMwXSkKCgojIyBTdW1tYXJpemUgYnkgUE0sIGRlcHRoCiMgMnBwCiMgUE0vZGVwdGgKcGFycy5maXQuMnBwLmRmLlBNIDwtIHBhcnMuZml0LjJwcC5kZiAlPiUKICAgIGZpbHRlcihlc3QgPT0gImZpdCIpICU+JQogICAgc2VsZWN0KCFjKGVzdCwgUE1lY29fZGVwdGgsIGVjbykpICU+JQogICAgZ3JvdXBfYnkoUE0sIGRlcHRoKSAlPiUKICAgIHN1bW1hcml6ZV9hbGwobGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCkpICU+JQogICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZvcm1hdCwgZGlnaXRzID0gMikKIyBwcmludCB0YWJsZQprbml0cjo6a2FibGUocGFycy5maXQuMnBwLmRmLlBNLAogICAgICAgICAgICAgY2FwdGlvbiA9ICJNZWFuIHBhcmFtZXRlciBlc3RpbWF0ZXMgYnkgcGFyZW50IG1hdGVyaWFsIChQTSkiLAogICAgICAgICAgICAgYWxpZ24gPSAiYyIpCiMgZWNvL2RlcHRoCnBhcnMuZml0LjJwcC5kZi5lY28gPC0gcGFycy5maXQuMnBwLmRmICU+JQogIGZpbHRlcihlc3QgPT0gImZpdCIpICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoZWNvLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgc2VsZWN0KCFjKGVzdCwgUE1lY29fZGVwdGgsIFBNKSkgJT4lCiAgZ3JvdXBfYnkoZWNvLCBkZXB0aCkgJT4lCiAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkgJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZvcm1hdCwgZGlnaXRzID0gMikKIyBwcmludCB0YWJsZQprbml0cjo6a2FibGUocGFycy5maXQuMnBwLmRmLmVjbywKICAgICAgICAgICAgIGNhcHRpb24gPSAiTWVhbiBwYXJhbWV0ZXIgZXN0aW1hdGVzIGJ5IGVjb3N5c3RlbSAoZWNvKSIsCiAgICAgICAgICAgICBhbGlnbiA9ICJjIikKYGBgCgpgYGB7ciBzZW5zLWZ1bi1maXRzfQojIyBsb29rIGF0IHNlbnNGdW4gb3V0cHV0CiMgd2l0aG91dCBjb25zdHJhaW50cwpzZW5zLjJwcCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLCBmdW5jdGlvbih4KSB4W1syXV0pCiMgd2l0aG91dCBzdG9jayBjb25zdHJhaW50CnNlbnMuMnBwMyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAzLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzMyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMzLCBmdW5jdGlvbih4KSB4W1syXV0pCiMgd2l0aCBzdG9jayBjb25zdHJhaW50CnNlbnMuMnBwM3MgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwM3MsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMzcyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMzcywgZnVuY3Rpb24oeCkgeFtbMl1dKQojIHdpdGggc3RvY2sgY29uc3RyYWludCwgdy9vIHJlc3AKc2Vucy4ycHA0LjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDQuMTAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHA0LjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDQuMzAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHM0LjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczQuMTAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHM0LjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczQuMzAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKIyB3aXRoIHN0b2NrIGNvbnN0cmFpbnQgKyByZXNwCnNlbnMuMnBwNHIuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNHIuMTAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHA0ci4zMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHA0ci4zMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwczRyLjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczRyLjEwLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzNHIuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNHIuMzAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKCgojIHBsb3Qgc2Vuc2l0aXZpdHkKIyB3L28gY29uc3RyYWludHMKbGFwcGx5KHNlbnMuMnBwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAicmVzcCIpKSkKbGFwcGx5KHNlbnMuMnBzLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAicmVzcCIpKSkKIyB3L28gc3RvY2sgY29uc3RyYWludApsYXBwbHkoc2Vucy4ycHAzLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHMzLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHAzcywgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgImNTdG9jayIpKSkKbGFwcGx5KHNlbnMuMnBzM3MsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCiMgd2l0aCBzdG9jayBjb25zdHJhaW50LCB3L28gcmVzcApsYXBwbHkoc2Vucy4ycHA0LjEwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHA0LjMwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHM0LjEwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHM0LjMwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQojIHdpdGggc3RvY2sgY29uc3RyYWludCArIHJlc3AKbGFwcGx5KHNlbnMuMnBwNHIuMTAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwcDRyLjMwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHM0ci4xMCwgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgImNTdG9jayIpKSkKbGFwcGx5KHNlbnMuMnBzNHIuMzAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCgoKIyBsb29rIGF0IGlkZW50aWZpYWJpbGl0eQppbmRlbi5kZi5meCA8LSBmdW5jdGlvbihscywgbW9kKSB7CiAgbGFwcGx5KGxzLCBmdW5jdGlvbih4KSB7CiAgICBkZiA8LSBjb2xsaW4oeCkKICAgIGlmIChtb2QgPT0gIjJwcCIpIHsKICAgICAgZGYkUGFyQ29tYm8gPC0gZmFjdG9yKGMoImsxICsgazIiLCAiazEgKyBnYW0iLCAiazIgKyBnYW0iLCAiazEgKyBrMiArIGdhbSIpKQogICAgfSBlbHNlIHsKICAgICAgZGYkUGFyQ29tYm8gPC0gZmFjdG9yKGMoImsxICsgazIiLCAiazEgKyBhMjEiLCAiazIgKyBhMjEiLCAiazEgKyBrMiArIGEyMSIpKQogICAgfQogICAgcmV0dXJuKGRmKQogIH0pCn0KCmlkZW4uMnBwIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBwLCBtb2QgPSAiMnBwIikKaWRlbi4ycHMgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMsIG1vZCA9ICIycHMiKQppZGVuLjJwcDMgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHAzLCBtb2QgPSAiMnBwIikKaWRlbi4ycHMzIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzMywgbW9kID0gIjJwcyIpCmlkZW4uMnBwM3MgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHAzcywgbW9kID0gIjJwcCIpCmlkZW4uMnBzM3MgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMzcywgbW9kID0gIjJwcyIpCiMgd2l0aCBzdG9jayBjb25zdHJhaW50LCB3L28gcmVzcAppZGVuLjJwcDQuMTAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHA0LjEwLCBtb2QgPSAiMnBwIikKaWRlbi4ycHA0LjMwIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBwNC4zMCwgbW9kID0gIjJwcCIpCmlkZW4uMnBzNC4xMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwczQuMTAsIG1vZCA9ICIycHMiKQppZGVuLjJwczQuMzAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHM0LjMwLCBtb2QgPSAiMnBzIikKIyB3aXRoIHN0b2NrIGNvbnN0cmFpbnQgKyByZXNwCmlkZW4uMnBwNHIuMTAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHA0ci4xMCwgbW9kID0gIjJwcCIpCmlkZW4uMnBwNHIuMzAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHA0ci4zMCwgbW9kID0gIjJwcCIpCmlkZW4uMnBzNHIuMTAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHM0ci4xMCwgbW9kID0gIjJwcyIpCmlkZW4uMnBzNHIuMzAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHM0ci4zMCwgbW9kID0gIjJwcyIpCgojIGlkZW50aWZpYWJpbGl0eSBwbG90IGZ1bmN0aW9uCmNvbGwucGxvdC5meCA8LSBmdW5jdGlvbihkZiwgbW9kLCBQTWVjb19kZXB0aCwgY29sLm1heCkgewogIGdncGxvdChkZiwgYWVzKE4sIGxvZyhjb2xsaW5lYXJpdHkpLCBjb2xvciA9IFBhckNvbWJvKSkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbG9nKDIwKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMy41LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjEpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBsb2coY29sLm1heCkpKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxLjUsIDMuNSksIGJyZWFrcyA9IGMoMiwgMykpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZShQTWVjb19kZXB0aCwgbW9kKSkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBpZiAobW9kID09ICIycHAiIHwgbW9kID09ICIycHAgKyBzdG9jayIpIHsKICAgICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICAgICBuYW1lID0gIlBhcmFtZXRlciBjb21iaW5hdGlvbiIsCiAgICAgICB2YWx1ZXMgPSBjKCJrMSArIGsyIiA9ICIjRUY0NzZGIiwKICAgICAgICAgICAgICAgICAgImsxICsgZ2FtIiA9ICIjRkZEMTY2IiwKICAgICAgICAgICAgICAgICAgImsyICsgZ2FtIiA9ICIjMTE4QUIyIiwKICAgICAgICAgICAgICAgICAgImsxICsgazIgKyBnYW0iID0gIjA3M0I0QyIpKSAKICAgIH0gZWxzZSB7CiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgICAgICBuYW1lID0gIlBhcmFtZXRlciBjb21iaW5hdGlvbiIsCiAgICAgICAgdmFsdWVzID0gYygiazEgKyBrMiIgPSAiI0VGNDc2RiIsCiAgICAgICAgICAgICAgICAgICJrMSArIGEyMSIgPSAiI0ZGRDE2NiIsCiAgICAgICAgICAgICAgICAgICJrMiArIGEyMSIgPSAiIzExOEFCMiIsCiAgICAgICAgICAgICAgICAgICJrMSArIGsyICsgYTIxIiA9ICIwNzNCNEMiKSkKICAgIH0KfQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcFtbaV1dLCBtb2QgPSAiMnBwIiwgbmFtZXMoaWRlbi4ycHApW2ldLCBtYXgoaWRlbi4ycHBbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwc1tbaV1dLCBtb2QgPSAiMnBzIiwgbmFtZXMoaWRlbi4ycHMpW2ldLCBtYXgoaWRlbi4ycHNbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwMyksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHAzW1tpXV0sIG1vZCA9ICIycHAiLCBuYW1lcyhpZGVuLjJwcDMpW2ldKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwM3MpLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBwM3NbW2ldXSwgbW9kID0gIjJwcCArIHN0b2NrIiwgbmFtZXMoaWRlbi4ycHAzcylbaV0pCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwczNbW2ldXSwgbW9kID0gIjJwcyIsIG5hbWVzKGlkZW4uMnBzMylbaV0pCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMzcyksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMzc1tbaV1dLCBtb2QgPSAiMnBzICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwczNzKVtpXSkKfSkKIyBzdG9jayBjb25zdHJhaW50LCB3L28gcmVzcApjb2wubWF4IDwtIG1heCh1bmxpc3QobGlzdChsYXBwbHkoaWRlbi4ycHM0LjEwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHM0LjMwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHA0LjEwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHA0LjMwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pKSkpCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHM0LjEwKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwczQuMTBbW2ldXSwgbW9kID0gIjJwcyArIHN0b2NrIiwgbmFtZXMoaWRlbi4ycHM0LjEwKVtpXSwgY29sLm1heCkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwczQuMzApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzNC4zMFtbaV1dLCBtb2QgPSAiMnBzICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwczQuMzApW2ldLCBjb2wubWF4KQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwNC4xMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHA0LjEwW1tpXV0sIG1vZCA9ICIycHAgKyBzdG9jayIsIG5hbWVzKGlkZW4uMnBwNC4xMClbaV0sIGNvbC5tYXgpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHA0LjMwKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcDQuMzBbW2ldXSwgbW9kID0gIjJwcCArIHN0b2NrIiwgbmFtZXMoaWRlbi4ycHA0LjMwKVtpXSwgY29sLm1heCkKfSkKCiMgc3RvY2sgY29uc3RyYWludCArIHJlc3AKY29sLm1heC5yIDwtIG1heCh1bmxpc3QobGlzdChsYXBwbHkoaWRlbi4ycHM0ci4xMCwgZnVuY3Rpb24oZGYpIGRmW1siY29sbGluZWFyaXR5Il1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHM0ci4zMCwgZnVuY3Rpb24oZGYpIGRmW1siY29sbGluZWFyaXR5Il1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHA0ci4xMCwgZnVuY3Rpb24oZGYpIGRmW1siY29sbGluZWFyaXR5Il1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaWRlbi4ycHA0ci4zMCwgZnVuY3Rpb24oZGYpIGRmW1siY29sbGluZWFyaXR5Il1dKSkpKQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwNHIuMTApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBwNHIuMTBbW2ldXSwgbW9kID0gIjJwcCIsIG5hbWVzKGlkZW4uMnBwNHIuMTApW2ldLCBjb2wubWF4KQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBwNHIuMzApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBwNHIuMzBbW2ldXSwgbW9kID0gIjJwcyIsIG5hbWVzKGlkZW4uMnBwNHIuMzApW2ldLCBjb2wubWF4KQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzNHIuMTApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzNHIuMTBbW2ldXSwgbW9kID0gIjJwcyArIHN0b2NrIiwgbmFtZXMoaWRlbi4ycHM0ci4xMClbaV0sIGNvbC5tYXgpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHM0ci4zMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHM0ci4zMFtbaV1dLCBtb2QgPSAiMnBzICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwczRyLjMwKVtpXSwgY29sLm1heCkKfSkKYGBgCgoKYGBge3IgcGxvdC1tb2RGaXQtcGFyc30KIyMgcGxvdCBwYXJzCnBhci5wbG90LmZ4IDwtIGZ1bmN0aW9uKG1vZCwgZGVwdGgsIHBhci5kZiwgaW5pdGlhbCA9IEZBTFNFKSB7CiAgcGFyLmRmICU+JQogICAgeyBpZiAoaW5pdGlhbCA9PSBUUlVFKSAuIGVsc2UgZmlsdGVyKC4sIGVzdCA9PSAiZml0IikgfSAlPiUKICAgIGZpbHRlcihkZXB0aCA9PSBkZXB0aCkgJT4lCiAgICBwaXZvdF9sb25nZXIoIShlc3Q6ZGVwdGgpLCBuYW1lc190byA9ICJwYXIiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICAgIG11dGF0ZShQTSA9IGZhY3RvcihQTSksCiAgICAgICAgICAgZWNvID0gZmFjdG9yKGVjbywgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogICAgZ2dwbG90KC4sIGFlcyhwYXIsIHZhbHVlLCBjb2xvciA9IFBNLCBzaGFwZSA9IGVjbykpICsKICAgICMgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDQpICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiQU4iID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgICBmYWNldF93cmFwKC4gfiBwYXIsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgZ2d0aXRsZShwYXN0ZTAoIm1vZEZpdCBwYXJzICIsIG1vZCwgIiAiLCBkZXB0aCkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKfQojIDAtMTAKIyAycHAKcGFyLnBsb3QuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKIyAycHAsIGdhbSA9IFsuNSwuOTVdCnBhci5wbG90LmZ4KG1vZCA9ICIycHAgKGdhbSA9IFswLjUsIDAuOTVdKSIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHAucDMuNS45NS5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIDJwcDIKcGFyLnBsb3QuZngobW9kID0gIjJwcDIiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBwMi5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIDJwcwpwYXIucGxvdC5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIDJwczIKcGFyLnBsb3QuZngobW9kID0gIjJwczIiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzMi5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQoKIyB3LyBhbmQgdy9vIHN0b2NrIGNvbnN0cmFpbnQKcGFyLnBsb3QuZngobW9kID0gIjJwcDMiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBwMy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBwM3MiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBwM3MuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwczMiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzMy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzM3MiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzM3MuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKCiMjIGZsdXggZXN0IGlucHV0cyBieSBlY28KIyBzdG9jayBhbmQgYnVsayAxNEMgb25seQpwYXIucGxvdC5meChtb2QgPSAiMnBwNCIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHA0LjEwLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHA0IiwKICAgICAgICAgICAgZGVwdGggPSAiMjAtMzAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHA0LjMwLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHM0IiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwczQuMTAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwczQiLAogICAgICAgICAgICBkZXB0aCA9ICIyMC0zMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwczQuMzAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKCiMgc3RvY2sgYW5kIGJ1bGsgKyByZXNwIDE0QwpwYXIucGxvdC5meChtb2QgPSAiMnBwNHIiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBwNHIuMTAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcDRyIiwKICAgICAgICAgICAgZGVwdGggPSAiMjAtMzAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHA0ci4zMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzNHIiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzNHIuMTAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwczRyIiwKICAgICAgICAgICAgZGVwdGggPSAiMjAtMzAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHM0ci4zMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpgYGAKCmBgYHtyIGZpdC1zb2MtaW59CiMjIEZpbmQgYmVzdCBpbnB1dHMKIyAycHAKaW4uZml0LjJwcCA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcCksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmZpdC4ycHApW2ldCiAgU09DIDwtIGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCJseXJfc29jIl0KICByZXR1cm4oaW4uZml0LmZ4KCIycHAiLCBwYXJzLmZpdC4ycHBbW2ldXSwgaW4uaVtpeC4xMF1bW2ldXSwgU09DKSkKfSkKbmFtZXMoaW4uZml0LjJwcCkgPC0gbmFtZXMobW9kLmZpdHMuMnBwKQojIDJwcCBnYW0gPSBbLjUsIC45NV0KaW4uZml0LjJwcC5wMy41Ljk1IDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwLnAzLjUuOTUpLCBmdW5jdGlvbihpKSB7CiAgUE1lY29fZGVwdGggPC0gbmFtZXMocGFycy5maXQuMnBwLnAzLjUuOTUpW2ldCiAgU09DIDwtIGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCJseXJfc29jIl0KICByZXR1cm4oaW4uZml0LmZ4KCIycHAiLCBwYXJzLmZpdC4ycHAucDMuNS45NVtbaV1dLCBpbi5pW2l4LjEwXVtbaV1dLCBTT0MpKQp9KQpuYW1lcyhpbi5maXQuMnBwLnAzLjUuOTUpIDwtIG5hbWVzKG1vZC5maXRzLjJwcC5wMy41Ljk1KQojIDJwcDIKaW4uZml0LjJwcDIgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAyKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuZml0LjJwcDIpW2ldCiAgU09DIDwtIGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCJseXJfc29jIl0KICByZXR1cm4oaW4uZml0LmZ4KCIycHAiLCBwYXJzLmZpdC4ycHAyW1tpXV0sIGluLmZseC5zdG9ja1tbaV1dLCBTT0MpKQp9KQpuYW1lcyhpbi5maXQuMnBwMikgPC0gbmFtZXMobW9kLmZpdHMuMnBwMikKIyAycHMKaW4uZml0LjJwcyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcyksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmZpdC4ycHMpW2ldCiAgU09DIDwtIGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCJseXJfc29jIl0KICByZXR1cm4oaW4uZml0LmZ4KCIycHMiLCBwYXJzLmZpdC4ycHNbW2ldXSwgaW4uaVtpeC4xMF1bW2ldXSwgU09DKSkKfSkKbmFtZXMoaW4uZml0LjJwcykgPC0gbmFtZXMobW9kLmZpdHMuMnBzKQojIDJwczIKaW4uZml0LjJwczIgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMyKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuZml0LjJwczIpW2ldCiAgU09DIDwtIGNzb2MuMTkuMF8zMFtbUE1lY29fZGVwdGhdXVsgLCJseXJfc29jIl0KICByZXR1cm4oaW4uZml0LmZ4KCIycHMiLCBwYXJzLmZpdC4ycHMyW1tpXV0sIGluLmZseC5zdG9ja1tbaV1dLCBTT0MpKQp9KQpuYW1lcyhpbi5maXQuMnBzMikgPC0gbmFtZXMobW9kLmZpdHMuMnBzMikKCiMjIENhbGMgbW9kZWxlZCBzdG9ja3MgYW5kIGNvbXBhcmUgd2l0aCBtZWFzdXJlZCBzdG9ja3MKIyAycHAKbW9kLnNvY3MuMnBwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBwIiwgcGFycy5maXQuMnBwW1tpXV0sIGluLmZpdC4ycHBbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHApCnNvY3MuMnBwLmxzIDwtIG1hcHBseShjYmluZCwKICAgICAgICAgICAgICAgICAgICAgIGNzb2MuMTkuMF8zMFtpeC4xMF0sIAogICAgICAgICAgICAgICAgICAgICAgbGFwcGx5KG1vZC5zb2NzLjJwcC5scywgY29sU3VtcyksIAogICAgICAgICAgICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSkKIyAycHAgZ2FtID0gWy41LCAuOTVdCm1vZC5zb2NzLjJwcC5wMy41Ljk1LmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwLnAzLjUuOTUpLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHAiLCBwYXJzLmZpdC4ycHAucDMuNS45NVtbaV1dLCBpbi5maXQuMnBwLnAzLjUuOTVbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwLnAzLjUuOTUubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcC5wMy41Ljk1KQpzb2NzLjJwcC5wMy41Ljk1bHMgPC0gbWFwcGx5KGNiaW5kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNzb2MuMTkuMF8zMFtpeC4xMF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShtb2Quc29jcy4ycHAucDMuNS45NS5scywgY29sU3VtcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpCiMgMnBwMgptb2Quc29jcy4ycHAyLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwMiksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcCIsIHBhcnMuZml0LjJwcDJbW2ldXSwgaW4uZml0LjJwcDJbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwMi5scykgPC0gbmFtZXMocGFycy5maXQuMnBwMikKCiMgMnBzCm1vZC5zb2NzLjJwcy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcyksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwc1tbaV1dLCBpbi5maXQuMnBzW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzKQpzb2NzLjJwcy5scyA8LSBtYXBwbHkoY2JpbmQsCiAgICAgICAgICAgICAgICAgICAgICBjc29jLjE5LjBfMzBbaXguMTBdLCAKICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShtb2Quc29jcy4ycHMubHMsIGNvbFN1bXMpLCAKICAgICAgICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpCiMgMnBzMgptb2Quc29jcy4ycHMyLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzMiksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwczJbW2ldXSwgaW4uZml0LjJwczJbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzMi5scykgPC0gbmFtZXMocGFycy5maXQuMnBzMikKCiMjIHN0b2NrIGFuZCBidWxrIDE0QyBjb3N0cyBvbmx5CiMgMnBwCm1vZC5zb2NzLjJwcDQuMTAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0LjEwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBwIiwgcGFycy5maXQuMnBwNC4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcDQuMTAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDQuMTApCm1vZC5zb2NzLjJwcDQuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0LjMwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBwIiwgcGFycy5maXQuMnBwNC4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcDQuMzAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDQuMzApCiMgMnBzCm1vZC5zb2NzLjJwczQuMTAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0LjEwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzNC4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwczQuMTAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczQuMTApCm1vZC5zb2NzLjJwczQuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0LjMwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzNC4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwczQuMzAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczQuMzApCgojIyBzdG9jayBhbmQgYnVsayArIHJlc3AgMTRDIGNvc3RzCiMgMnBwCm1vZC5zb2NzLjJwcDRyLjEwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwNHIuMTApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHAiLCBwYXJzLmZpdC4ycHA0ci4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcDRyLjEwLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHA0ci4xMCkKbW9kLnNvY3MuMnBwNHIuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0ci4zMCksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcCIsIHBhcnMuZml0LjJwcDRyLjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwNHIuMzAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDRyLjMwKQojIDJwcwptb2Quc29jcy4ycHM0ci4xMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczRyLjEwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzNHIuMTBbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHM0ci4xMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBzNHIuMTApCm1vZC5zb2NzLjJwczRyLjMwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzNHIuMzApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHMiLCBwYXJzLmZpdC4ycHM0ci4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwczRyLjMwLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHM0ci4zMCkKCgojIyBSZXR1cm4gZGF0YSBmcmFtZXMgb2YgbW9kZWwgZml0cyB3aXRoIGFkanVzdGVkIGlucHV0cyBhbmQgb3B0aW1hbCBwYXJhbWV0ZXJzCiMgMnBwClR3b3BwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHApLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwcFtbaV1dLCBpbi5maXQuMnBwW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcCIpCn0pCm5hbWVzKFR3b3BwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcCkKIyAycHAgZ2FtID0gWy41LCAuOTVdClR3b3BwLnAzLjUuOTUuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcC5wMy41Ljk1KSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHAucDMuNS45NVtbaV1dLCBpbi5maXQuMnBwLnAzLjUuOTVbW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIikKfSkKbmFtZXMoVHdvcHAucDMuNS45NS5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHAucDMuNS45NSkKIyAycHAyClR3b3BwMi5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwMiksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBwMltbaV1dLCBpbi5maXQuMnBwMltbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHAiKQp9KQpuYW1lcyhUd29wcDIuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBwMikKIyAycHMKVHdvcHMuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcyksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBzW1tpXV0sIGluLmZpdC4ycHNbW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIikKfSkKbmFtZXMoVHdvcHMuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzKQojIDJwczIKVHdvcHMyLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMyKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHMyW1tpXV0sIGluLmZpdC4ycHMyW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBUUlVFKQp9KQpuYW1lcyhUd29wczIuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzMikKCiMjIHN0b2NrIGFuZCBidWxrIDE0QyBjb3N0cyBvbmx5CiMgMnBwClR3b3BwNC4xMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwNC4xMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBwNC4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcCIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHA0LjEwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDQuMTApClR3b3BwNC4zMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwNC4zMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBwNC4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcCIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHA0LjMwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDQuMzApCiMgMnBzClR3b3BzNC4xMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzNC4xMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBzNC4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHM0LjEwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczQuMTApClR3b3BzNC4zMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzNC4zMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBzNC4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHM0LjMwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczQuMzApCgojIyBzdG9jayBhbmQgYnVsayArIHJlc3AgMTRDIGNvc3RzCiMgMnBwClR3b3BwNHIuMTAuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcDRyLjEwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHA0ci4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcCIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHA0ci4xMC5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHA0ci4xMCkKVHdvcHA0ci4zMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwNHIuMzApLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwcDRyLjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wcDRyLjMwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDRyLjMwKQojIDJwcwpUd29wczRyLjEwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0ci4xMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBzNHIuMTBbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpCn0pCm5hbWVzKFR3b3BzNHIuMTAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzNHIuMTApClR3b3BzNHIuMzAuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczRyLjMwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHM0ci4zMFtbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHM0ci4zMC5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHM0ci4zMCkKYGBgCgpgYGB7ciBwbG90LXNvYy1zdG9ja3N9CiMgUGxvdCBvcHRpbWl6ZWQgbW9kZWwgU09DIHN0b2Nrcwptb2Quc29jcy5kZi5meCA8LSBmdW5jdGlvbihtb2QsIG1vZC5zb2NzLmxzLCBwb29scykgewogIG4gPC0gdmFwcGx5KG1vZC5zb2NzLmxzLCBucm93LCBudW1lcmljKDEpKQogIHJldHVybihkYXRhLmZyYW1lKFNPQyA9IGRvLmNhbGwocmJpbmQsIG1vZC5zb2NzLmxzKSwKICAgICAgICAgICAgICAgICAgICBwb29sID0gcmVwKHBvb2xzLCBsZW5ndGgobW9kLnNvY3MubHMpKSwKICAgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IHJlcChuYW1lcyhtb2Quc29jcy5scyksIG4pLAogICAgICAgICAgICAgICAgICAgIE1vZGVsID0gcmVwKG1vZCwgc3VtKG4pKSkpICAgICAgIAp9CiMgcnVuIGZ4CiMgbW9kLnNvY3MuMnAuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcCIsIG1vZC5zb2NzLjJwcC5scywgYygiZmFzdCIsICJzbG93IikpCiMgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHMiLCBtb2Quc29jcy4ycHMubHMsIGMoImZhc3QiLCAic2xvdyIpKQojICAgICAgICAgICAgICAgICAgICAgICAgICxtb2Quc29jcy5kZi5meCgiMnBwIFsuNSwuOTVdIiwgbW9kLnNvY3MuMnBwLnAzLjUuOTUubHMsIGMoImZhc3QiLCAic2xvdyIpKQojICAgICAgICAgICAgICAgICAgICAgICAgICxtb2Quc29jcy5kZi5meCgiMnBzMiIsIG1vZC5zb2NzLjJwczIubHMsIGMoImZhc3QiLCAic2xvdyIpKQojICAgICAgICAgICAgICAgICAgICAgICAgICxtb2Quc29jcy5kZi5meCgiMnBwMiIsIG1vZC5zb2NzLjJwcDIubHMsIGMoImZhc3QiLCAic2xvdyIpKQojICAgICAgICAgICAgICAgICAgICAgICAgICkKbW9kLnNvY3MuMnAuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcCIsIG1vZC5zb2NzLjJwcC5scywgYygiZmFzdCIsICJzbG93IikpCiAgICAgICAgICAgICAgICAgICAgICAgICxtb2Quc29jcy5kZi5meCgiMnBzIiwgbW9kLnNvY3MuMnBzLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkKICAgICAgICAgICAgICAgICAgICAgICAgKQoKCiMgc3RvY2tzIGFuZCBidWxrIDE0QyBvbmx5Cm1vZC5zb2NzLjJwNC4xMC5kZiA8LSByYmluZChtb2Quc29jcy5kZi5meCgiMnBwNCAwLTEwIiwgbW9kLnNvY3MuMnBwNC4xMC5scywgYygiZmFzdCIsICJzbG93IikpLCBtb2Quc29jcy5kZi5meCgiMnBzNCAwLTEwIiwgbW9kLnNvY3MuMnBzNC4xMC5scywgYygiZmFzdCIsICJzbG93IikpKQptb2Quc29jcy4ycDQuMzAuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcDQgMjAtMzAiLCBtb2Quc29jcy4ycHA0LjMwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkgLG1vZC5zb2NzLmRmLmZ4KCIycHM0IDIwLTMwIiwgbW9kLnNvY3MuMnBzNC4zMC5scywgYygiZmFzdCIsICJzbG93IikpKQoKIyBzdG9ja3MgYW5kIGJ1bGsgKyByZXNwIDE0Qwptb2Quc29jcy4ycDRyLjEwLmRmIDwtIHJiaW5kKG1vZC5zb2NzLmRmLmZ4KCIycHA0ciAwLTEwIiwgbW9kLnNvY3MuMnBwNHIuMTAubHMsIGMoImZhc3QiLCAic2xvdyIpKSwgbW9kLnNvY3MuZGYuZngoIjJwczRyIDAtMTAiLCBtb2Quc29jcy4ycHM0ci4xMC5scywgYygiZmFzdCIsICJzbG93IikpKQptb2Quc29jcy4ycDRyLjMwLmRmIDwtIHJiaW5kKG1vZC5zb2NzLmRmLmZ4KCIycHA0ciAyMC0zMCIsIG1vZC5zb2NzLjJwcDRyLjMwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkgLG1vZC5zb2NzLmRmLmZ4KCIycHM0ciAyMC0zMCIsIG1vZC5zb2NzLjJwczRyLjMwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkpCgojIGNvbWJpbmUgaW5wdXRzIHRvIGNvbXBhcmUKIyBpbi5maXRzLmRmIDwtIHBpdm90X2xvbmdlcihkby5jYWxsKGJpbmRfcm93cywgbGlzdChpbi5maXQuMnBwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluLmZpdC4ycHAucDMuNS45NSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbi5maXQuMnBwMiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbi5maXQuMnBzLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluLmZpdC4ycHMyKSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlcnl0aGluZygpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlBNZWNvX2RlcHRoIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiaW5wdXRzIikKIyBpbi5maXRzLmRmJG1vZCA8LSByZXAoYygiMnBwIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAiMnBwLjUuOTUiLAojICAgICAgICAgICAgICAgICAgICAgICAgICIycHAyIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAiMnBzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAiMnBzMiIpLAojICAgICAgICAgICAgICAgICAgICAgICBlYWNoID0gOSkKaW4uZml0cy5kZiA8LSBwaXZvdF9sb25nZXIoZG8uY2FsbChiaW5kX3Jvd3MsIGxpc3QoaW4uZml0LjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW4uZml0LjJwcykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlBNZWNvX2RlcHRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImlucHV0cyIpCmluLmZpdHMuZGYkbW9kIDwtIHJlcChjKCIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAiMnBzIiksCiAgICAgICAgICAgICAgICAgICAgICBlYWNoID0gOSkKICAgICAgICAgICAgICAgICAgICAgICAgCiMjIHBsb3Qgc3RvY2tzCiMgc3RvY2sgYW5kIGJ1bGsgMTRDIG9ubHkKbW9kLnNvY3MuMnA0LjEwLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCm1vZC5zb2NzLjJwNC4zMC5kZiAlPiUKICBtdXRhdGUoUE0gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDEsIDIpLAogICAgICAgICBlY28gPSBmYWN0b3Ioc3Vic3RyKFBNZWNvX2RlcHRoLCAzLCA0KSwgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogIGdncGxvdCguLCBhZXMocG9vbCwgU09DLCBmaWxsID0gTW9kZWwpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhQTSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQojIHN0b2NrIGFuZCBidWxrICsgcmVzcCAxNEMKbW9kLnNvY3MuMnA0ci4xMC5kZiAlPiUKICBtdXRhdGUoUE0gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDEsIDIpLAogICAgICAgICBlY28gPSBmYWN0b3Ioc3Vic3RyKFBNZWNvX2RlcHRoLCAzLCA0KSwgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogIGdncGxvdCguLCBhZXMocG9vbCwgU09DLCBmaWxsID0gTW9kZWwpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhQTSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQptb2Quc29jcy4ycDRyLjMwLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGlucHV0cwppbi5maXRzLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgICMgTW9kZWwgPSBmYWN0b3IoTW9kZWwsIGxldmVscyA9IGMoIjJwcCBbLjUsLjk1XSIsICIycHAiLCAiMnBzIikpLAogICAgICAgICBlY28gPSBmYWN0b3Ioc3Vic3RyKFBNZWNvX2RlcHRoLCAzLCA0KSwgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogIGdncGxvdCguLCBhZXMobW9kLCBpbnB1dHMsIGZpbGwgPSBtb2QpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhQTSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCmBgYHtyIHBsb3Qtb3B0LW1vZC0ycHB9CiMgcGxvdCBmeApUd29wLmZpdC5wbG90LmZ4IDwtIGZ1bmN0aW9uKGZpdDEsIGZpdDEubmFtZSwgZml0MiwgZml0Mi5uYW1lLCBmaXQzID0gTlVMTCwgZml0My5uYW1lID0gTlVMTCkgewogIGxhcHBseShzZXFfYWxvbmcoZml0MSksIGZ1bmN0aW9uKGkpIHsKICAgIFBNZWNvIDwtIHN1YnN0cihuYW1lcyhmaXQxKVtpXSwgMSwgNCkKICAgIGx5cl9ib3QgPC0gc3Vic3RyKG5hbWVzKGZpdDEpW2ldLCAKICAgICAgICAgICAgICAgICAgICAgIG5jaGFyKG5hbWVzKGZpdDEpW2ldKSAtIDEsIAogICAgICAgICAgICAgICAgICAgICAgbmNoYXIobmFtZXMoZml0MSlbaV0pKQogICAgbHlyX3RvcCA8LSBpZmVsc2UobHlyX2JvdCA9PSAxMCwgMCwgaWZlbHNlKGx5cl9ib3QgPT0gMjAsIDEwLCAyMCkpCiAgICBQTWVjb19kZXB0aCA8LSBuYW1lcyhmaXQxKVtpXQogICAgY29uLmRmIDwtIGNvbi5kZi5meChQTWVjb19kZXB0aCkKICAgIHBsb3QuZGYgPC0gcmJpbmQoZml0MVtbaV1dLAogICAgICAgICAgICAgICAgICAgICBmaXQyW1tpXV0sCiAgICAgICAgICAgICAgICAgICAgIGZpdDNbW2ldXSkKICAgIHBsb3QuZGYkTW9kZWwgPC0gZmFjdG9yKGMocmVwKGZpdDEubmFtZSwgbnJvdyhmaXQxW1tpXV0pKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGZpdDIubmFtZSwgbnJvdyhmaXQyW1tpXV0pKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGZpdDMubmFtZSwgbnJvdyhmaXQzW1tpXV0pKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKGZpdDEubmFtZSwgZml0Mi5uYW1lLCBmaXQzLm5hbWUpKQogICAgcmV0dXJuKHBsb3QuZGYgJT4lCiAgICAgICAgICAgICBmaWx0ZXIocG9vbCA9PSAiYnVsayBDIiB8IHBvb2wgPT0gInJlc3BpcmF0aW9uIiB8IHBvb2wgPT0gImF0bSIpICU+JQogICAgICAgICAgICAgZ2dwbG90KC4sIGFlcyh5ZWFycywgZDE0QywgY29sb3IgPSBwb29sKSkgKwogICAgICAgICAgICAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IE1vZGVsKSkgKwogICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gY29uLmRmLCBhZXMoWWVhciwgZDE0YywgY29sb3IgPSBwb29sKSwgc2l6ZSA9IDMpICsKICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgICAgICAgICAgICAgbmFtZSA9ICJNb2RlbCBwb29sIiwKICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYXRtIiA9IDgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgImJ1bGsgQyIgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICJmYXN0IiA9ICIjRDgxQjYwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAic2xvdyIgPSAiIzFFODhFNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgInJlc3BpcmF0aW9uIiA9ICIjRkZDMTA3IikpICsKICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5NTAsIDIwMjIpKSArCiAgICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMChQTWVjb19kZXB0aCwgIiAycCBtb2QgZml0cyIpKSArCiAgICAgICAgICAgICB4bGFiKCJZZWFyIikgKwogICAgICAgICAgICAgeWxhYihleHByZXNzaW9uKCcnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkpCiAgfSkKfQojIDJwIG1vZEZpdCBvcHRpbWFsIG1vZGVsIGNvbXBhcmlzb24KVHdvcC5maXRzLnBsb3RzIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHAuZml0cywgIjJwcCIsIFR3b3BzLmZpdHMsICIycHMiKQpUd29wLmZpdHMucGxvdHMKIyBUd29wLmZpdHMucGxvdHMyIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHAuZml0cywgIjJwcCIsIFR3b3BwLnAzLjUuOTUuZml0cywgIjJwcCBnYW0gPSBbLjUsIC45NV0iKQojIFR3b3AuZml0cy5wbG90czIKVHdvcC5maXRzLnBsb3RzMyA8LSBUd29wLmZpdC5wbG90LmZ4KFR3b3BwLnAzLjUuOTUuZml0cywgIjJwcCBnYW0gPSBbLjUsIC45NV0iLCBUd29wcDIuZml0cywgIjJwcDIiKQpUd29wLmZpdHMucGxvdHMzCgojIyBjb21wYXJlIGZpdHMgdy8gYW5kIHcvbyByZXNwIGNvbnN0cmFpbnQgKDJwNCBtb2RzKQojIDJwcApUd29wcDQuZml0cy5wbG90cy4xMCA8LSBUd29wLmZpdC5wbG90LmZ4KFR3b3BwNC4xMC5maXRzLCAiMnBwNCAwLTEwY20gdy9vIHJlc3AiLCBUd29wcDRyLjEwLmZpdHMsICIycHA0ciAwLTEwY20gdy8gcmVzcCIpClR3b3BwNC5maXRzLnBsb3RzLjMwIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHA0LjMwLmZpdHMsICIycHA0IDIwLTMwY20gdy9vIHJlc3AiLCBUd29wcDRyLjEwLmZpdHMsICIycHA0ciAyMC0zMGNtIHcvIHJlc3AiKQojIDJwcwpUd29wczQuZml0cy5wbG90cy4xMCA8LSBUd29wLmZpdC5wbG90LmZ4KFR3b3BzNC4xMC5maXRzLCAiMnBzNCAwLTEwY20gdy9vIHJlc3AiLCBUd29wczRyLjEwLmZpdHMsICIycHM0ciAwLTEwY20gdy8gcmVzcCIpClR3b3BzNC5maXRzLnBsb3RzLjMwIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHM0LjMwLmZpdHMsICIycHM0IDIwLTMwY20gdy9vIHJlc3AiLCBUd29wczRyLjEwLmZpdHMsICIycHM0ciAyMC0zMGNtIHcvIHJlc3AiKQojIHBsb3QKVHdvcHA0LmZpdHMucGxvdHMuMTAKVHdvcHA0LmZpdHMucGxvdHMuMzAKVHdvcHM0LmZpdHMucGxvdHMuMTAKVHdvcHM0LmZpdHMucGxvdHMuMzAKYGBgCgpgYGB7ciBTQUItb2JzfQpwIDwtIHNyYS50cy5hbGwgJT4lCiAgICBmaWx0ZXIoZDE0YyA+IC0yMDApICU+JQogICAgZmlsdGVyKEVDTyAhPSAicmYiKSAlPiUKICAgIGZpbHRlcihseXJfYm90ID09IDIwKSAlPiUKICAgIGZpbHRlcih5ZWFyICE9IDIwMDkpICU+JQogICAgZ2dwbG90KC4sIGFlcyh5ZWFyLCBkMTRjKSkgKwogICAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1R5cGUpLCBzaXplID0gMy41KSArCiAgICBnZW9tX3BhdGgoYWVzKGNvbG9yID0gcG0sIGxpbmV0eXBlID0gVHlwZSksIHNpemUgPSAxLCBhbHBoYSA9IDAuMykgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgICBhZXMoeW1pbiA9IGQxNGNfbCwgCiAgICAgICAgICAgIHltYXggPSBkMTRjX3UsCiAgICAgICAgICAgIGNvbG9yID0gcG0pLCAKICAgICAgICB3aWR0aCA9IC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0gKHR5cGUpIiwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIChpbmMpIiA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoaW5jKSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKGluYykiID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtIChidWxrKSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIChidWxrKSIgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIChidWxrKSIgPSAxNykpICsKICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgICB5bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogICAgeGxhYigiWWVhciIpICsKICAgIGdndGl0bGUoIkJ1bGsvaW5jIDEwLTIwIGNtIikgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQpnZ3NhdmUoInNyYS50cy5wcHdmMjAuYmxrLmluYy5wZGYiLCBwLCBkcGkgPSAzMDAsIHdpZHRoID0gNi45NywgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQojIGluYy9idWxrIHByb2ZpbGVzCnAgPC0gc3JhLjE5LjAxLjA5ICU+JQogIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogIHNlbGVjdChZZWFyLCBQTSwgRUNPLCBQTWVjbywgbHlyX2JvdCwgZDE0YywgZDE0Y19zZCkgJT4lCiAgbXV0YXRlKFR5cGUgPSAiYnVsayIsCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgeWVhciA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFllYXIpKSkgJT4lCiAgc2VsZWN0KC1kMTRjX3NkKSAlPiUKICBiaW5kX3Jvd3MoLiwKICAgICAgICAgICAgc3JhLjE5LjAxLmluYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgUE0sIEVDTywgUE1lY28sIGx5cl9ib3QsIGQxNGMsIGQxNGNfbWluLCBkMTRjX21heCkgJT4lCiAgICAgICAgICAgICAgcmVuYW1lKGQxNGNfbCA9IGQxNGNfbWluLAogICAgICAgICAgICAgICAgICAgICBkMTRjX3UgPSBkMTRjX21heCkgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKFR5cGUgPSAiaW5jIikKICApICU+JQogIG11dGF0ZShkZXB0aCA9IGZhY3RvcihseXJfYm90KSwKICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSksCiAgICAgICAgIGVjb1R5cGUgPSBwYXN0ZTAoZWNvLCAiICgiLCBUeXBlLCAiKSIpKQpnZ3NhdmUoInNyYS50cy5wcHdmMjAuYmxrLnBkZiIsIHAsIGRwaSA9IDMwMCwgd2lkdGggPSA2Ljk3LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIpCmBgYAoKYGBge3IgU0FCLW1vZGZpdHN9CiMjIyBSdW4gbW9kZml0CiMjIDE0QyBidWxrIG9ubHkKIyAwLTEwCm1vZC5zZW5zLmZpdHMuMnBzLjEwYiA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTk5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgb25seSIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjEwYikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMTBiLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4xMGIiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyAjIDIwLTMwCiMgbW9kLnNlbnMuZml0cy4ycHMuMzBiIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjE1KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMDUsIC4wMDAxLCAuMDAwNCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgb25seSIpCiMgbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMzBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KIyBzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjMwYiwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMzBiIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgbW9kLmZpdHMuMnBzLjMwYiA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmdW5jdGlvbih4KSB4W1sxXV0pCgojIyAxNEMgKGJ1bGsgKyByZXNwKQojIDAtMTAKbW9kLnNlbnMuZml0cy4ycHMuMTBiciA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTk5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMTBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMTBiciwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMTBiciIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQojIDEwLTIwLCBsYWcgPSA1Cm1vZC5zZW5zLmZpdHMuMnBzLjIwYnIubCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWcgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAyLCAuMDAwMSwgLjAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMiKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4yMGJyLmwpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjIwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjIwYnIubCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMjBici5sIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgIyAyMC0zMAojIG1vZC5zZW5zLmZpdHMuMnBzLjMwYnIgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMTUpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAwNSwgLjAwMDEsIC4wMDA0KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMiKQojIG5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjMwYnIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQojIHNhdmUobW9kLnNlbnMuZml0cy4ycHMuMzBiciwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMzBiciIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQojIG1vZC5maXRzLjJwcy4zMGJyIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4zMGJyLCBmdW5jdGlvbih4KSB4W1sxXV0pCgojIyAxNEMgYnVsayArIHN0b2NrcwojIDAtMTAKbW9kLnNlbnMuZml0cy4ycHMuMTBicyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTk5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAyLCAuMDAwMSwgLjAwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgYnVsayArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjEwYnMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjEwYnMsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzLjEwYnMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzLjEwYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYnMsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAjIDIwLTMwCiMgbW9kLnNlbnMuZml0cy4ycHMuMzBiIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjE1KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMDUsIC4wMDAxLCAuMDAwNCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgb25seSIpCiMgbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMzBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KIyBzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjMwYiwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMzBiIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgbW9kLmZpdHMuMnBzLjMwYiA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmdW5jdGlvbih4KSB4W1sxXV0pCgojIyAxNEMgKyBjU3RvY2sgKDE0QyByZXNwLCAxNEMgYnVsaywgc3RvY2tzKQojIDAtMTAKbW9kLnNlbnMuZml0cy4ycHMuMTByYnMgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAyLCAuMDAwMSwgLjAwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMTByYnMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjEwcmJzLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4xMHJicyIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHMuMTByYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwcmJzLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMTAtMjAKIyB3L28gbGFnCm1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAyLCAuMDAwMSwgLjAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4yMHJicykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMjByYnMsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzLjIwcmJzIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgdy8gbGFnID0gMTIKbW9kLnNlbnMuZml0cy4ycHMuMjByYnMubCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFnID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzLmwpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjIwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzLmwsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzLjIwcmJzLmwiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyAjIDIwLTMwCiMgbW9kLnNlbnMuZml0cy4ycHMuMzBiIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjE1KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMDUsIC4wMDAxLCAuMDAwNCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgb25seSIpCiMgbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMzBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KIyBzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjMwYiwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMzBiIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgbW9kLmZpdHMuMnBzLjMwYiA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmdW5jdGlvbih4KSB4W1sxXV0pCmBgYAoKYGBge3IgU0FCLW1vZC1maXRzfQojIFNBQiBmaXRzCmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMuMTBiXzIwMjEtMDQtMDcuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzLjEwYnJfMjAyMS0wNC0wNy5SZGF0YSIpCmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMuMTBic18yMDIxLTA0LTA3LlJkYXRhIikKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy4xMHJic18yMDIxLTA0LTA3LlJkYXRhIikKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy4yMHJic18yMDIxLTA0LTEyLlJkYXRhIikKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy4yMHJicy5sXzIwMjEtMDQtMTMuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzLjIwYnIubF8yMDIxLTA0LTEzLlJkYXRhIikKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL3BhcnMuaS4ycHNfMjAyMS0wNC0wNi5SZGF0YSIpCgojIGV4dHJhY3QgbW9kIGZpdHMKbW9kLmZpdHMuMnBzLjEwYiA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTBiLCBmdW5jdGlvbih4KSB4W1sxXV0pCm1vZC5maXRzLjJwcy4xMGJzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4xMGJzLCBmdW5jdGlvbih4KSB4W1sxXV0pCm1vZC5maXRzLjJwcy4xMGJyIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4xMGJyLCBmdW5jdGlvbih4KSB4W1sxXV0pCm1vZC5maXRzLjJwcy4xMHJicyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTByYnMsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKbW9kLmZpdHMuMnBzLjIwcmJzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMHJicywgZnVuY3Rpb24oeCkgeFtbMV1dKQptb2QuZml0cy4ycHMuMjByYnMubCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMjByYnMubCwgZnVuY3Rpb24oeCkgeFtbMV1dKQptb2QuZml0cy4ycHMuMjBici5sIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMGJyLmwsIGZ1bmN0aW9uKHgpIHhbWzFdXSkgCiAgCiMgU2Vuc2l0aXZpdHkvSWRlbnRpZmlhYmlsaXR5CiMjIyMjCiMgZXh0cmFjdCBhdCBzZW5zRnVuIG91dHB1dApzZW5zLjJwcy4xMGIgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYiwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcy4xMGJyIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4xMGJyLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzLjEwYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYnMsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMuMTByYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwcmJzLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzLjIwcmJzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMHJicywgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcy4yMHJicy5sIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMHJicy5sLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzLjIwYnIubCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMjBici5sLCBmdW5jdGlvbih4KSB4W1syXV0pCgojIHBsb3Qgc2Vuc2l0aXZpdHkKbGFwcGx5KHNlbnMuMnBzLjEwYiwgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgInJlc3AiKSkpCmxhcHBseShzZW5zLjJwcy4xMGJyLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAicmVzcCIpKSkKbGFwcGx5KHNlbnMuMnBzLjEwYnMsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJyZXNwIikpKQpsYXBwbHkoc2Vucy4ycHMuMTByYnMsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJyZXNwIikpKQoKIyBsb29rIGF0IGlkZW50aWZpYWJpbGl0eQppZGVuLjJwcy4xMGIgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMuMTBiLCBtb2QgPSAiMnBzIikKaWRlbi4ycHMuMTBiciA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4xMGJyLCBtb2QgPSAiMnBzIikKaWRlbi4ycHMuMTBicyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4xMGJzLCBtb2QgPSAiMnBzIikKaWRlbi4ycHMuMTByYnMgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMuMTByYnMsIG1vZCA9ICIycHMiKQppZGVuLjJwcy4yMHJicyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4yMHJicywgbW9kID0gIjJwcyIpCmlkZW4uMnBzLjIwcmJzLmwgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMuMjByYnMubCwgbW9kID0gIjJwcyIpCmlkZW4uMnBzLjIwYnIubCA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4yMGJyLmwsIG1vZCA9ICIycHMiKQoKIyBwbG90CmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMuMTBicyksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMuMTBic1tbaV1dLCBtb2QgPSAiMnBzIiwgCiAgICAgICAgICAgICAgIG5hbWVzKGlkZW4uMnBzLjEwYnMpW2ldLCAKICAgICAgICAgICAgICAgbWF4KGlkZW4uMnBzLjEwYnNbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzLjEwYnIpLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzLjEwYnJbW2ldXSwgbW9kID0gIjJwcyIsIAogICAgICAgICAgICAgICBuYW1lcyhpZGVuLjJwcy4xMGJyKVtpXSwgCiAgICAgICAgICAgICAgIG1heChpZGVuLjJwcy4xMGJyW1tpXV1bImNvbGxpbmVhcml0eSJdKSkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwcy4xMHJicyksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMuMTByYnNbW2ldXSwgbW9kID0gIjJwcyIsIAogICAgICAgICAgICAgICBuYW1lcyhpZGVuLjJwcy4xMHJicylbaV0sIAogICAgICAgICAgICAgICBtYXgoaWRlbi4ycHMuMTByYnNbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzLjIwcmJzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcy4yMHJic1tbaV1dLCBtb2QgPSAiMnBzIiwgCiAgICAgICAgICAgICAgIG5hbWVzKGlkZW4uMnBzLjIwcmJzKVtpXSwgCiAgICAgICAgICAgICAgIG1heChpZGVuLjJwcy4yMHJic1tbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMuMjByYnMubCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMuMjByYnMubFtbaV1dLCBtb2QgPSAiMnBzIiwgCiAgICAgICAgICAgICAgIG5hbWVzKGlkZW4uMnBzLjIwcmJzLmwpW2ldLCAKICAgICAgICAgICAgICAgbWF4KGlkZW4uMnBzLjIwcmJzLmxbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzLjIwYnIubCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMuMjBici5sW1tpXV0sIG1vZCA9ICIycHMiLCAKICAgICAgICAgICAgICAgbmFtZXMoaWRlbi4ycHMuMjBici5sKVtpXSwgCiAgICAgICAgICAgICAgIG1heChpZGVuLjJwcy4yMGJyLmxbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQojIyMjIwoKIyBFeHRyYWN0IG9wdGltaXplZCBwYXJzIGZyb20gbW9kZml0IG91dHB1dAojIyMjIwojIyBidWxrIDE0YyBvbmx5CiMgMC0xMApwYXJzLmZpdC4ycHMuMTBiIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMTBiLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMTBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYiA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjMwYiwgIltbIiwgMSkKIyBuYW1lcyhwYXJzLmZpdC4ycHMuMzBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KCiMjIHJlc3AgKyBidWxrIDE0YwojIDAtMTAKcGFycy5maXQuMnBzLjEwYnIgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4xMGJyLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMTBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCiMgMTAtMjAgdy8gbGFnID0gNXkKcGFycy5maXQuMnBzLjIwYnIubCA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjIwYnIubCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzLjIwYnIubCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGJyIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMzBiciwgIltbIiwgMSkKIyBuYW1lcyhwYXJzLmZpdC4ycHMuMzBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCgojIyBidWxrIDE0YyArIHN0b2NrcwojIDAtMTAKcGFycy5maXQuMnBzLjEwYnMgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4xMGJzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMTBicykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGJyIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMzBiciwgIltbIiwgMSkKIyBuYW1lcyhwYXJzLmZpdC4ycHMuMzBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCgojIyByZXNwLCBidWxrIDE0Yywgc3RvY2tzCiMgMC0xMApwYXJzLmZpdC4ycHMuMTByYnMgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4xMHJicywgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzLjEwcmJzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KIyAxMC0yMApwYXJzLmZpdC4ycHMuMjByYnMgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4yMHJicywgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzLjIwcmJzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4yMF0KIyAxMC0yMCB3LyBsYWcgPSAxMnkKcGFycy5maXQuMnBzLjIwcmJzLmwgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4yMHJicy5sLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMjByYnMubCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGJyIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMzBiciwgIltbIiwgMSkKIyBuYW1lcyhwYXJzLmZpdC4ycHMuMzBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCiMjIyMjCgojIFNPQyBzdG9ja3MKIyMjIyMKIyB3L28gc3RvY2sgY29uc3RyYWludAptb2Quc29jcy4ycHMuMTBiLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwYiksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwcy4xMGJbW2ldXSwgaW4uZXN0W1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcy4xMGIubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMGIpCm1vZC5zb2NzLjJwcy4xMGJyLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwYnIpLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHMiLCBwYXJzLmZpdC4ycHMuMTBicltbaV1dLCBpbi5lc3RbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzLjEwYnIubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMGJyKQpzb2NzLjJwcy4xMGJyLmxzIDwtIG1hcHBseShjYmluZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY3NvYy4xOS4wXzMwW2l4LjEwXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShtb2Quc29jcy4ycHMuMTBici5scywgY29sU3VtcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBTSU1QTElGWSA9IEZBTFNFKQojIHcvIHN0b2NrIGNvbnN0cmFpbnQKbW9kLnNvY3MuMnBzLjEwYnMubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBicyksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwcy4xMGJzW1tpXV0sIGluLmVzdFtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHMuMTBicy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwYnMpCm1vZC5zb2NzLjJwcy4xMHJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMHJicyksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwcy4xMHJic1tbaV1dLCBpbi5lc3RbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzLjEwcmJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTByYnMpCm1vZC5zb2NzLjJwcy4yMHJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4yMHJicyksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwcy4yMHJic1tbaV1dLCBpbi5lc3RbaXguMjBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcy4yMHJicy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjIwcmJzKQpzb2NzLjJwcy4xMHJicy5scyA8LSBtYXBwbHkoY2JpbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNzb2MuMTkuMF8zMFtpeC4xMF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkobW9kLnNvY3MuMnBzLjEwcmJzLmxzLCBjb2xTdW1zKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpCgojIyBtYWtlIGRmIGZvciBwbG90dGluZwojIHJlc3AgKyBidWxrLCB3LyBhbmQgdy9vIHN0b2Nrcwptb2Quc29jcy4ycHMuMTBicnJicy5kZiA8LSByYmluZChtb2Quc29jcy5kZi5meCgiMnBzIHcvbyBzdG9jayIsIG1vZC5zb2NzLjJwcy4xMGJyLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHMgdy8gc3RvY2siLCBtb2Quc29jcy4ycHMuMTByYnMubHMsIGMoImZhc3QiLCAic2xvdyIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsZGF0YS5mcmFtZShTT0MgPSB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KGxhcHBseShjc29jLjE5LjBfMzBbaXguMTBdLCAiW1siLCAxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgMikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1vZGVsID0gIm1lYXN1cmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9vbCA9ICJ0b3RhbCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyBidWxrICsgc3RvY2ssIHZzLiByZXNwLCBidWxrLCArIHN0b2NrCm1vZC5zb2NzLjJwcy4xMGJzcmJzLmRmIDwtIHJiaW5kKG1vZC5zb2NzLmRmLmZ4KCIycHMgYnVsayArIHN0b2NrIG9ubHkiLCBtb2Quc29jcy4ycHMuMTBicy5scywgYygiZmFzdCIsICJzbG93IikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxtb2Quc29jcy5kZi5meCgiMnBzIGJ1bGssIHJlc3AsICsgc3RvY2siLCBtb2Quc29jcy4ycHMuMTByYnMubHMsIGMoImZhc3QiLCAic2xvdyIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsZGF0YS5mcmFtZShTT0MgPSB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KGxhcHBseShjc29jLjE5LjBfMzBbaXguMTBdLCAiW1siLCAxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgMikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1vZGVsID0gIm1lYXN1cmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9vbCA9ICJ0b3RhbCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCgojIyBwbG90Cm1vZC5zb2NzLjJwcy4xMGJycmJzLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCm1vZC5zb2NzLjJwcy4xMGJzcmJzLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMjIyMjCgojIyMgU3VtbWFyaXplIG9wdGltaXplZCBwYXIgZGF0YSBmb3IgcGxvdHRpbmcKIyMgYnVsayAxNGMgb25seQojIDAtMTAKcGFycy5maXQuMnBzLjEwYi5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMTBiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4xMF0pCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGIuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjMwYiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMzBdKQoKIyMgcmVzcCArIGJ1bGsgMTRjCiMgMC0xMApwYXJzLmZpdC4ycHMuMTBici5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4xMGJyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyAxMC0yMApwYXJzLmZpdC4ycHMuMjBici5sLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjIwYnIubCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4xMF0pCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGJyLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMzBiciwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjMwXSkKCiMjIGJ1bGsgMTRjICsgc3RvY2tzCiMgMC0xMApwYXJzLmZpdC4ycHMuMTBicy5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4xMGJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYnIuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4zMGJyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMzBdKQoKIyMgcmVzcCwgYnVsaywgc3RvY2tzCiMgMC0xMApwYXJzLmZpdC4ycHMuMTByYnMuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMTByYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojIDEwLTIwCnBhcnMuZml0LjJwcy4yMHJicy5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4yMHJicywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4yMF0pCiMgdy8gbGFnCnBhcnMuZml0LjJwcy4yMHJicy5sLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjIwcmJzLmwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMjBdKQojICMgMjAtMzAKIyBwYXJzLmZpdC4ycHMuMzBici5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjMwYnIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4zMF0pCgojIyMgUGFyIGZpdHMKcGFyLnBsb3QuZngobW9kID0gIjJwcyBidWxrIDE0YyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMTBiLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHMgcmVzcCArIGJ1bGsgMTRjIiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4xMGJyLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHMgYnVsayAxNGMgKyBzdG9ja3MiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjEwYnMuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyByZXNwLCBidWxrLCBzdG9ja3MiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjEwcmJzLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHMgcmVzcCwgYnVsaywgc3RvY2tzIiwKICAgICAgICAgICAgZGVwdGggPSAiMTAtMjAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMjByYnMuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyByZXNwLCBidWxrLCBzdG9ja3MiLAogICAgICAgICAgICBkZXB0aCA9ICIxMC0yMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4yMHJicy5sLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHMgcmVzcCwgYnVsayIsCiAgICAgICAgICAgIGRlcHRoID0gIjEwLTIwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjIwYnIubC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIHBhci5wbG90LmZ4KG1vZCA9ICIycHMgYnVsayAxNGMiLAojICAgICAgICAgICAgIGRlcHRoID0gIjIwLTMwIiwKIyAgICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMzBiLmRmLAojICAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKIyBwYXIucGxvdC5meChtb2QgPSAiMnBzIHJlc3AgKyBidWxrIDE0YyIsCiMgICAgICAgICAgICAgZGVwdGggPSAiMjAtMzAiLAojICAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4zMGJyLmRmLAojICAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKCiMjIyBGaXQgbW9kZWxzIHdpdGggb3B0aW1pemVkIHBhcnMKIyMgYnVsayAxNEMgb25seQojIDAtMTAKVHdvcHMuMTBiLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBiKSwgZnVuY3Rpb24oaSkgewogIHRyeUNhdGNoKAogICAgcGFyLmZ4KHBhcnMuZml0LjJwcy4xMGJbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAogICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMoVHdvcHMuMTBiLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMGIpCiMgIyAyMC0zMAojIFR3b3BzLjMwYi5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjMwYiksIGZ1bmN0aW9uKGkpIHsKIyAgIHRyeUNhdGNoKAojICAgICBwYXIuZngocGFycy5maXQuMnBzLjMwYltbaV1dLCBpbi5lc3RbaXguMzBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiMgICAgIGVycm9yID0gZnVuY3Rpb24gKGUpIHtjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKX0pCiMgfSkKIyBuYW1lcyhUd29wcy4zMGIuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjMwYikKCiMjIHJlc3AgKyBidWxrIDE0QwojIDAtMTAKVHdvcHMuMTBici5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwYnIpLCBmdW5jdGlvbihpKSB7CiAgdHJ5Q2F0Y2goCiAgICBwYXIuZngocGFycy5maXQuMnBzLjEwYnJbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAogICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMoVHdvcHMuMTBici5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTBicikKIyAxMC0yMApUd29wcy4yMGJyLmwuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4yMGJyLmwpLCBmdW5jdGlvbihpKSB7CiAgdHJ5Q2F0Y2goCiAgICBwYXIuZngocGFycy5maXQuMnBzLjIwYnIubFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhUd29wcy4yMGJyLmwuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjIwYnIubCkKIyAjIDIwLTMwCiMgVHdvcHMuMzBici5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjMwYnIpLCBmdW5jdGlvbihpKSB7CiMgICB0cnlDYXRjaCgKIyAgICAgcGFyLmZ4KHBhcnMuZml0LjJwcy4zMGJyW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKSwKIyAgICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKIyB9KQojIG5hbWVzKFR3b3BzLjMwYnIuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjMwYnIpCgojIyBidWxrIDE0QyArIHN0b2NrcwojIDAtMTAKVHdvcHMuMTBicy5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwYnMpLCBmdW5jdGlvbihpKSB7CiAgdHJ5Q2F0Y2goCiAgICBwYXIuZngocGFycy5maXQuMnBzLjEwYnNbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAogICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMoVHdvcHMuMTBicy5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTBicykKCiMjIHJlc3AsIGJ1bGssIHN0b2NrcwojIDAtMTAKVHdvcHMuMTByYnMuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMHJicyksIGZ1bmN0aW9uKGkpIHsKICB0cnlDYXRjaCgKICAgIHBhci5meChwYXJzLmZpdC4ycHMuMTByYnNbW2ldXSwgaW4uZXN0W2l4LjEwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAogICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMoVHdvcHMuMTByYnMuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwcmJzKQojIDEwLTIwClR3b3BzLjIwcmJzLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMjByYnMpLCBmdW5jdGlvbihpKSB7CiAgdHJ5Q2F0Y2goCiAgICBwYXIuZngocGFycy5maXQuMnBzLjIwcmJzW1tpXV0sIGluLmVzdFtpeC4yMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKSwKICAgIGVycm9yID0gZnVuY3Rpb24gKGUpIHtjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKX0pCn0pCm5hbWVzKFR3b3BzLjIwcmJzLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4yMHJicykKCiMgIyByZW1vdmUgbnVsbCBlbnRyaWVzCiMgVHdvcHMuMTBiLmZpdHMgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgVHdvcHMuMTBiLmZpdHMpCiMgVHdvcHMuMzBiLmZpdHMgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgVHdvcHMuMzBiLmZpdHMpCiMgVHdvcHMuMTBici5maXRzIDwtIEZpbHRlcihOZWdhdGUoaXMubnVsbCksIFR3b3BzLjEwYnIuZml0cykKIyBUd29wcy4zMGJyLmZpdHMgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgVHdvcHMuMzBici5maXRzKQoKIyBMb29rIGF0IHJvbGUgb2YgcmVzcCBjb25zdHJhaW50IGluIGZpdAojIGxhcHBseShzZXFfYWxvbmcoVHdvcHMuMTBiLmZpdHMpLCBmdW5jdGlvbihpKSB7CiMgICBDMTQuMnAucGxvdC5meChUd29wcy4xMGIuZml0c1tbaV1dLAojICAgICAgICAgICAgICAgICAgY29uLmRmID0gY29uLmRmLmZ4KG5hbWVzKFR3b3BzLjEwYi5maXRzKVtpXSksIAojICAgICAgICAgICAgICAgICAgbW9kID0gIjJwcyBidWxrIG9ubHkiLAojICAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4xMGIuZml0cylbaV0pCiMgfSkKbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4xMGJyLmZpdHMpLCBmdW5jdGlvbihpKSB7CiAgQzE0LjJwLnBsb3QuZngoVHdvcHMuMTBici5maXRzW1tpXV0sIAogICAgICAgICAgICAgICAgIGNvbi5kZiA9IGNvbi5kZi5meChuYW1lcyhUd29wcy4xMGJyLmZpdHMpW2ldKSwgCiAgICAgICAgICAgICAgICAgbW9kID0gIjJwcyBidWxrICsgcmVzcCIsCiAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4xMGJyLmZpdHMpW2ldKQp9KQojIGxhcHBseShzZXFfYWxvbmcoVHdvcHMuMTBicy5maXRzKSwgZnVuY3Rpb24oaSkgewojICAgQzE0LjJwLnBsb3QuZngoVHdvcHMuMTBicy5maXRzW1tpXV0sCiMgICAgICAgICAgICAgICAgICBjb24uZGYgPSBjb24uZGYuZngobmFtZXMoVHdvcHMuMTBicy5maXRzKVtpXSksIAojICAgICAgICAgICAgICAgICAgbW9kID0gIjJwcyBidWxrICsgc3RvY2siLAojICAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4xMGJzLmZpdHMpW2ldKQojIH0pCmxhcHBseShzZXFfYWxvbmcoVHdvcHMuMTByYnMuZml0cyksIGZ1bmN0aW9uKGkpIHsKICBDMTQuMnAucGxvdC5meChUd29wcy4xMHJicy5maXRzW1tpXV0sIAogICAgICAgICAgICAgICAgIGNvbi5kZiA9IGNvbi5kZi5meChuYW1lcyhUd29wcy4xMHJicy5maXRzKVtpXSksIAogICAgICAgICAgICAgICAgIG1vZCA9ICJidWxrLCByZXNwLCBzdG9jayIsCiAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4xMHJicy5maXRzKVtpXSkKfSkKIyAxMC0yMApsYXBwbHkoc2VxX2Fsb25nKFR3b3BzLjIwcmJzLmZpdHMpLCBmdW5jdGlvbihpKSB7CiAgQzE0LjJwLnBsb3QuZngoVHdvcHMuMjByYnMuZml0c1tbaV1dLCAKICAgICAgICAgICAgICAgICBjb24uZGYgPSBjb24uZGYuZngobmFtZXMoVHdvcHMuMjByYnMuZml0cylbaV0pLCAKICAgICAgICAgICAgICAgICBtb2QgPSAiYnVsaywgcmVzcCwgc3RvY2siLAogICAgICAgICAgICAgICAgIFBNZWNvX2RlcHRoID0gbmFtZXMoVHdvcHMuMjByYnMuZml0cylbaV0pCn0pCiMgbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4zMGIuZml0cyksIGZ1bmN0aW9uKGkpIHsKIyAgIEMxNC4ycC5wbG90LmZ4KFR3b3BzLjMwYi5maXRzW1tpXV0sCiMgICAgICAgICAgICAgICAgICBjb24uZGYgPSBjb24uZGYuZngobmFtZXMoVHdvcHMuMzBiLmZpdHMpW2ldKSwgCiMgICAgICAgICAgICAgICAgICBtb2QgPSAiMnBzIGJ1bGsgb25seSIsCiMgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjMwYi5maXRzKVtpXSkKIyB9KQojIGxhcHBseShzZXFfYWxvbmcoVHdvcHMuMzBici5maXRzKSwgZnVuY3Rpb24oaSkgewojICAgQzE0LjJwLnBsb3QuZngoVHdvcHMuMzBici5maXRzW1tpXV0sIAojICAgICAgICAgICAgICAgICAgY29uLmRmID0gY29uLmRmLmZ4KG5hbWVzKFR3b3BzLjMwYnIuZml0cylbaV0pLCAKIyAgICAgICAgICAgICAgICAgIG1vZCA9ICIycHMgYnVsayArIHJlc3AiLAojICAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4zMGJyLmZpdHMpW2ldKQojIH0pCgojIyBTaG93IHJvbGUgb2YgcmVzcCBpbiBjb25zdHJhaW5pbmcgbW9kZWxzCiMgR1J3ZiAwLTEwClR3b3AuZml0LnBsb3QuZngoVHdvcHMuMTBicy5maXRzW3doaWNoKG5hbWVzKFR3b3BzLjEwYnMuZml0cykgPT0gIkdSd2ZfMC0xMCIpXSwgCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20sIGJ1bGsgMTRjICsgc3RvY2siLCAKICAgICAgICAgICAgICAgICBUd29wcy4xMHJicy5maXRzW3doaWNoKG5hbWVzKFR3b3BzLjEwcmJzLmZpdHMpID09ICJHUndmXzAtMTAiKV0sCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20sIHJlc3AgJiBidWxrIDE0YyArIHN0b2NrIikKIyBCU3JmIDAtMTAKVHdvcC5maXQucGxvdC5meChUd29wcy4xMGJyLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTBici5maXRzKSA9PSAiQlNyZl8wLTEwIildLCAKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3LyByZXNwIiwgCiAgICAgICAgICAgICAgICAgVHdvcHMuMTBiLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTBiLmZpdHMpID09ICJCU3JmXzAtMTAiKV0sCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20gdy9vIHJlc3AiKQpUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjEwcmJzLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTByYnMuZml0cykgPT0gIkJTcmZfMC0xMCIpXSwKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3LyByZXNwLCBidWxrLCBzdG9ja3MiLAogICAgICAgICAgICAgICAgIFR3b3BzLjEwYnMuZml0c1t3aGljaChuYW1lcyhUd29wcy4xMGJzLmZpdHMpID09ICJCU3JmXzAtMTAiKV0sCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20gdy9vIHJlc3AgKGJ1bGsgKyBzdG9ja3Mgb25seSkiKQpUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjEwcmJzLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTByYnMuZml0cykgPT0gIkJTd2ZfMTAtMjAiKV0sCiAgICAgICAgICAgICAgICAgIkJhc2FsdC9jb29sIDEwLTIwIiwKICAgICAgICAgICAgICAgICBUd29wcy4xMHJicy5maXRzW3doaWNoKG5hbWVzKFR3b3BzLjEwcmJzLmZpdHMpID09ICJHUndmXzEwLTIwIildLAogICAgICAgICAgICAgICAgICJHcmFuaXRlL2Nvb2wgMTAtMjAiKQoKIyBjb21wYXJlIHJlc3AgKyBidWxrIGZpdHMgdy8gYW5kIHcvbyBzdG9ja3MKVHdvcC5maXQucGxvdC5meChUd29wcy4xMHJicy5maXRzLCAKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3LyByZXNwLCBidWxrLCBzdG9ja3MiLCAKICAgICAgICAgICAgICAgICBUd29wcy4xMGJyLmZpdHMsCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20gdy8gcmVzcCArIGJ1bGssIG5vIHN0b2NrIikKIyBjb21wYXJlIHJlc3AgKyBidWxrIGZpdHMgdy8gYW5kIHcvbyBzdG9ja3MKVHdvcC5maXQucGxvdC5meChUd29wcy4xMGJzLmZpdHMsIAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtLCBidWxrIDE0YyArIHN0b2NrIiwgCiAgICAgICAgICAgICAgICAgVHdvcHMuMTByYnMuZml0cywKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSwgcmVzcCAmIGJ1bGsgMTRjICsgc3RvY2siKQojIGNvbXBhcmUgQlN3ZiBhbmQgR1J3ZiAxMC0yMApCU0dSd2YyMC5jb24uZGYgPC0gY2JpbmQocmJpbmQoY29uLmRmLmZ4KCJCU3dmXzEwLTIwIiksIGNvbi5kZi5meCgiR1J3Zl8xMC0yMCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtID0gZmFjdG9yKHJlcChjKCJiYXNhbHQiLCAiZ3Jhbml0ZSIpLCBlYWNoID0gYygxMSkpKSkKQlNHUndmMjAuY29uLmRmIDwtIEJTR1J3ZjIwLmNvbi5kZlstd2hpY2goQlNHUndmMjAuY29uLmRmJFllYXIgPT0gMjAwOS41KSwgXQpBTkdSd2YyMC5jb24uZGYgPC0gY2JpbmQocmJpbmQoY29uLmRmLmZ4KCJCU3dmXzEwLTIwIiksIGNvbi5kZi5meCgiR1J3Zl8xMC0yMCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtID0gZmFjdG9yKHJlcChjKCJiYXNhbHQiLCAiZ3Jhbml0ZSIpLCBlYWNoID0gYygxMSkpKSkKQlNHUndmMjAuY29uLmRmIDwtIEJTR1J3ZjIwLmNvbi5kZlstd2hpY2goQlNHUndmMjAuY29uLmRmJFllYXIgPT0gMjAwOS41KSwgXQphdG0uMTRjMiA8LSBUd29wcy4yMHJicy5maXRzJGBCU3dmXzEwLTIwYFtUd29wcy4yMHJicy5maXRzJGBCU3dmXzEwLTIwYCR5ZWFycyA+PSAxOTUwICYgVHdvcHMuMjByYnMuZml0cyRgQlN3Zl8xMC0yMGAkcG9vbCA9PSAiYXRtIiwgXQojIHBsb3QKcCA8LSByYmluZChUd29wcy4yMHJicy5maXRzJGBCU3dmXzEwLTIwYCwKICAgICAgVHdvcHMuMjByYnMuZml0cyRgR1J3Zl8xMC0yMGApICU+JQogIG11dGF0ZShwbSA9IHJlcChjKCJiYXNhbHQiLCAiZ3Jhbml0ZSIpLCAKICAgICAgICAgICAgICAgICAgZWFjaCA9IG5yb3coVHdvcHMuMjByYnMuZml0cyRgQlN3Zl8xMC0yMGApKSkgJT4lCiAgZmlsdGVyKHBvb2wgPT0gImJ1bGsgQyIgfCBwb29sID09ICJyZXNwaXJhdGlvbiIpICU+JQogIGdncGxvdCguLCBhZXMoeWVhcnMsIGQxNEMpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjMikgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBwb29sLCBjb2xvciA9IHBtKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IEJTR1J3ZjIwLmNvbi5kZiwgCiAgICAgICAgICAgICBhZXMoWWVhciwgZDE0YywgY29sb3IgPSBwbSwgc2hhcGUgPSBwb29sKSwgCiAgICAgICAgICAgICBzaXplID0gMi41LAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgbmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgdmFsdWVzID0gYygiYmFzYWx0IiA9ICJyZWQiLAogICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgIG5hbWUgPSAiIiwKICAgIHZhbHVlcyA9IGMoImJ1bGsgQyIgPSAxNiwKICAgICAgICAgICAgICAgInJlc3BpcmF0aW9uIiA9IDEpKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICBuYW1lID0gIlBvb2wiLAogICB2YWx1ZXMgPSBjKCJidWxrIEMiID0gMSwKICAgICAgICAgICAgICAicmVzcGlyYXRpb24iID0gMikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxOTUwLCAyMDIyKSkgKwogIHhsYWIoIlllYXIiKSArCiAgeWxhYihleHByZXNzaW9uKCcnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoInNyYS4ycHMuQlNHUndmMjAucGRmIiwgcCwgZHBpID0gMzAwLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUsIHVuaXRzID0gImluIikKIyBjb21wYXJlIHJlc3AgKyBidWxrIGZpdHMgdy8gYW5kIHcvbyBzdG9ja3MKVHdvcC5maXQucGxvdC5meChUd29wcy4yMGJyLmwuZml0cywgCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20sIGJ1bGsgMTRjICsgc3RvY2siLCAKICAgICAgICAgICAgICAgICBUd29wcy4yMHJicy5maXRzLAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtLCByZXNwICYgYnVsayAxNGMgKyBzdG9jayIpCiMjIyMjCgojIGFnZXMgYW5kIHRyYW5zaXQgdGltZXMKIyMjIyMKIyAycHMKU0EuMnBzLjIwLnJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4yMHJicyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHMuMjByYnNbW2ldXVsxOjJdCiAgdGMgPC0gcGFycy5maXQuMnBzLjIwcmJzW1tpXV1bM10KICBJbiA8LSBpbi5lc3RbaXguMjBdW1tpXV0KICBBIDwtIGRpYWcoLWtzKQogIEFbMiwgMV0gPC0gdGMgKiBrc1sxXQogIHJldHVybihzeXN0ZW1BZ2UoQSA9IEEsIHUgPSBjKEluLCAwKSkpCn0pCm5hbWVzKFNBLjJwcy4yMC5yYnMubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4yMHJicykKbGFwcGx5KFNBLjJwcy4yMC5yYnMubHMsICJbWyIsIDEpCgojIyBUcmFuc2l0IHRpbWUKIyAycHMKVFQuMnBzLjIwLnJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4yMHJicyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHMuMjByYnNbW2ldXVsxOjJdCiAgdGMgPC0gcGFycy5maXQuMnBzLjIwcmJzW1tpXV1bM10KICBJbiA8LSBpbi5lc3RbaXguMjBdW1tpXV0KICBBIDwtIGRpYWcoLWtzKQogIEFbMiwgMV0gPC0gdGMgKiBrc1sxXQogIHJldHVybih0cmFuc2l0VGltZShBID0gQSwgdSA9IGMoSW4sIDApKSkKfSkKbmFtZXMoVFQuMnBzLjIwLnJicy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjIwcmJzKQpsYXBwbHkoVFQuMnBzLjIwLnJicy5scywgIltbIiwgMSkKIyAwLTEwClRULk1BLjJwcy4xMC5yYnMubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTByYnMpLCBmdW5jdGlvbihpKSB7CiAga3MgPC0gcGFycy5maXQuMnBzLjEwcmJzW1tpXV1bMToyXQogIHRjIDwtIHBhcnMuZml0LjJwcy4xMHJic1tbaV1dWzNdCiAgSW4gPC0gaW4uZXN0W2l4LjEwXVtbaV1dCiAgQSA8LSBkaWFnKC1rcykKICBBWzIsIDFdIDwtIHRjICoga3NbMV0KICBUVCA8LSB0cmFuc2l0VGltZShBID0gQSwgdSA9IGMoSW4sIDApKQogIEFnZSA8LSBzeXN0ZW1BZ2UoQSA9IEEsIHUgPSBjKEluLCAwKSkKICByZXR1cm4obGlzdChUVCA9IFRUJG1lYW5UcmFuc2l0VGltZSwgQWdlID0gQWdlJG1lYW5TeXN0ZW1BZ2UpKQp9KQpuYW1lcyhUVC5NQS4ycHMuMTAucmJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTByYnMpCmxhcHBseShUVC5NQS4ycHMuMTAucmJzLmxzLCB1bmxpc3QpCiMgCmFnZUQuMnBzLjEwLnJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMHJicyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHMuMTByYnNbW2ldXVsxOjJdCiAgdGMgPC0gcGFycy5maXQuMnBzLjEwcmJzW1tpXV1bM10KICBJbiA8LSBpbi5lc3RbaXguMTBdW1tpXV0KICBBIDwtIGRpYWcoLWtzKQogIEFbMiwgMV0gPC0gdGMgKiBrc1sxXQogIHJldHVybihzeXN0ZW1BZ2UoQSA9IEEsIHUgPSBjKEluLCAwKSkpCn0pCm5hbWVzKGFnZUQuMnBzLjEwLnJicy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwcmJzKQpgYGAKCmBgYHtyIG1vZEZpdC0ycC1jb21wYXJpc29ufQojIGNvbXBhcmUgb3V0cHV0IG9mIDJwcCBhbmQgMnBzIG1vZGVsIGZpdHMKbWVyZ2Uoc3NyLjJwcC5kZiwgc3NyLjJwcy5kZiwgYnkgPSAiUE1lY29fZGVwdGgiLCBzdWZmaXhlcyA9IGMoIl8ycHAiLCAiXzJwcyIpKSAlPiUKICBtdXRhdGUoc3NyXzJwcCA9IHJvdW5kKHNzcl8ycHAsIDEpLAogICAgICAgICBzc3JfMnBzID0gcm91bmQoc3NyXzJwcywgMSksCiAgICAgICAgIGRpZiA9IHNzcl8ycHAgLSBzc3JfMnBzKQptZXJnZSh2YXJfbXMuMnBwLmRmLAogICAgICB2YXJfbXMuMnBzLmRmLAogICAgICBieSA9IGMoIlBNZWNvX2RlcHRoIiwgInZhciIpLAogICAgICBzdWZmaXhlcyA9IGMoIl8ycHAiLCAiXzJwcyIpKSAlPiUKICBtdXRhdGUodmFyX21zXzJwcCA9IHJvdW5kKHZhcl9tc18ycHAsIDQpLAogICAgICAgICB2YXJfbXNfMnBzID0gcm91bmQodmFyX21zXzJwcywgNCksCiAgICAgICAgIGRpZiA9IHZhcl9tc18ycHAgLSB2YXJfbXNfMnBzKQoKIyMgUGxvdAojIFNTUiwgUE0KcmJpbmQoc3NyLjJwcC5kZiwgc3NyLjJwcy5kZikgJT4lCiAgbXV0YXRlKG1vZCA9IHJlcChjKCIycHAiLCAiMnBzIiksIGVhY2ggPSBucm93KHNzci4ycHAuZGYpKSwKICAgICAgICAgUE0gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDEsIDIpLAogICAgICAgICBlY28gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpKSAlPiUKICBncm91cF9ieShQTSwgbW9kKSAlPiUKICBzdW1tYXJpemUobWVhbi5zc3IgPSBtZWFuKHNzciksIHNkID0gc2Qoc3NyKSkgJT4lCiAgbXV0YXRlKGVycl91ID0gbWVhbi5zc3IgKyBzZC9zcXJ0KDMpLAogICAgICAgICBlcnJfbCA9IG1lYW4uc3NyIC0gc2Qvc3FydCgzKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhtb2QsIG1lYW4uc3NyLCBmaWxsID0gUE0pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWF4ID0gZXJyX3UsIHltaW4gPSBlcnJfbCksIAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwKICAgIHdpZHRoID0gLjMpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gUE0pICsKICBnZ3RpdGxlKCJTU1IgMi1wb29sIG1vZGVscyAwLTEwIGNtIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgU1NSLCBlY28KcmJpbmQoc3NyLjJwcC5kZiwgc3NyLjJwcy5kZikgJT4lCiAgbXV0YXRlKG1vZCA9IHJlcChjKCIycHAiLCAiMnBzIiksIGVhY2ggPSBucm93KHNzci4ycHAuZGYpKSwKICAgICAgICAgUE0gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDEsIDIpLAogICAgICAgICBlY28gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpKSAlPiUKICBncm91cF9ieShlY28sIG1vZCkgJT4lCiAgc3VtbWFyaXplKG1lYW4uc3NyID0gbWVhbihzc3IpLCBzZCA9IHNkKHNzcikpICU+JQogIG11dGF0ZShlcnJfdSA9IG1lYW4uc3NyICsgc2Qvc3FydCgzKSwKICAgICAgICAgZXJyX2wgPSBtZWFuLnNzciAtIHNkL3NxcnQoMykpICU+JQogIGdncGxvdCguLCBhZXMobW9kLCBtZWFuLnNzciwgZmlsbCA9IGVjbykpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltYXggPSBlcnJfdSwgeW1pbiA9IGVycl9sKSwgCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLAogICAgd2lkdGggPSAuMykgKwogIGZhY2V0X3dyYXAoLiB+IGVjbykgKwogIGdndGl0bGUoIlNTUiAyLXBvb2wgbW9kZWxzIDAtMTAgY20gKGVjbykiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgdmFyX21zLCBQTQpyYmluZCh2YXJfbXMuMnBwLmRmLCB2YXJfbXMuMnBzLmRmKSAlPiUKICBtdXRhdGUobW9kID0gcmVwKGMoIjJwcCIsICIycHMiKSwgZWFjaCA9IG5yb3codmFyX21zLjJwcC5kZikpLAogICAgICAgICBQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCkpICU+JQogIGdyb3VwX2J5KHZhciwgUE0sIG1vZCkgJT4lCiAgc3VtbWFyaXplKG1lYW4udmFyX21zID0gbWVhbih2YXJfbXMpLCBzZCA9IHNkKHZhcl9tcykpICU+JQogIG11dGF0ZShlcnJfdSA9IG1lYW4udmFyX21zICsgc2Qvc3FydCgzKSwKICAgICAgICAgZXJyX2wgPSBtZWFuLnZhcl9tcyAtIHNkL3NxcnQoMykpICU+JQogIGdncGxvdCguLCBhZXMobW9kLCBtZWFuLnZhcl9tcywgZmlsbCA9IFBNKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1heCA9IGVycl91LCB5bWluID0gZXJyX2wpLCAKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksCiAgICB3aWR0aCA9IC4zKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImdyYW5pdGUiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSkgKwogIGZhY2V0X3dyYXAoLiB+IHZhciwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2d0aXRsZSgiUmVzaWR1YWwgZXJyb3IgMi1wb29sIG1vZGVscyAwLTEwIGNtIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgdmFyX21zLCBlY28KcmJpbmQodmFyX21zLjJwcC5kZiwgdmFyX21zLjJwcy5kZikgJT4lCiAgbXV0YXRlKG1vZCA9IHJlcChjKCIycHAiLCAiMnBzIiksIGVhY2ggPSBucm93KHZhcl9tcy4ycHAuZGYpKSwKICAgICAgICAgUE0gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDEsIDIpLAogICAgICAgICBlY28gPSBzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpKSAlPiUKICBncm91cF9ieSh2YXIsIGVjbywgbW9kKSAlPiUKICBzdW1tYXJpemUobWVhbi52YXJfbXMgPSBtZWFuKHZhcl9tcyksIHNkID0gc2QodmFyX21zKSkgJT4lCiAgbXV0YXRlKGVycl91ID0gbWVhbi52YXJfbXMgKyBzZC9zcXJ0KDMpLAogICAgICAgICBlcnJfbCA9IG1lYW4udmFyX21zIC0gc2Qvc3FydCgzKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhtb2QsIG1lYW4udmFyX21zLCBmaWxsID0gZWNvKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1heCA9IGVycl91LCB5bWluID0gZXJyX2wpLCAKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksCiAgICB3aWR0aCA9IC4zKSArCiAgZmFjZXRfd3JhcCguIH4gdmFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZ3RpdGxlKCJSZXNpZHVhbCBlcnJvciAyLXBvb2wgbW9kZWxzIDAtMTAgY20iKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7ciBhZ2VzLXR0LW1vZEZpdH0KIyMgU3lzdGVtIGFnZQojIDJwcApTQS4ycHAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHApLCBmdW5jdGlvbihpKSB7CiAga3MgPC0gcGFycy5maXQuMnBwW1tpXV1bMToyXQogIGdhbSA8LSBwYXJzLmZpdC4ycHBbW2ldXVszXQogIEluIDwtIGluLmZpdC4ycHBbW2ldXQogIHJldHVybihzeXN0ZW1BZ2UoLCB1ID0gSW4pKQp9KQpuYW1lcyhTQS4ycHAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcCkKIyAycHAgZ2FtID0gWy41LCAuOTVdClNBLjJwcC5wMy41Ljk1LmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwLnAzLjUuOTUpLCBmdW5jdGlvbihpKSB7CiAga3MgPC0gcGFycy5maXQuMnBwLnAzLjUuOTVbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV1bM10KICBJbiA8LSBpbi5maXQuMnBwLnAzLjUuOTVbW2ldXQogIHJldHVybihzeXN0ZW1BZ2UoQSA9IC0xICogZGlhZyhrcyksIHUgPSBjKEluICogZ2FtLCBJbiAqICgxIC0gZ2FtKSkpKQp9KQpuYW1lcyhTQS4ycHAucDMuNS45NS5scykgPC0gbmFtZXMocGFycy5maXQuMnBwLnAzLjUuOTUpCiMgMnBzClNBLjJwcy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHNbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwc1tbaV1dWzNdCiAgSW4gPC0gaW4uZml0LjJwc1tbaV1dCiAgcmV0dXJuKHN5c3RlbUFnZShBID0gLTEgKiBkaWFnKGtzKSwgdSA9IGMoSW4gKiBnYW0sIEluICogKDEgLSBnYW0pKSkpCn0pCm5hbWVzKFNBLjJwcy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzKQoKIyMgVHJhbnNpdCB0aW1lCiMgMnBwClRULjJwcC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcCksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHBbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwcFtbaV1dWzNdCiAgSW4gPC0gaW4uZml0LjJwcFtbaV1dCiAgcmV0dXJuKHRyYW5zaXRUaW1lKEEgPSAtMSAqIGRpYWcoa3MpLCB1ID0gYyhJbiAqIGdhbSwgSW4gKiAoMSAtIGdhbSkpKSkKfSkKbmFtZXMoVFQuMnBwLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHApCiMgMnBwIGdhbSA9IFsuNSwgLjk1XQpUVC4ycHAucDMuNS45NS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcC5wMy41Ljk1KSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV1bMToyXQogIGdhbSA8LSBwYXJzLmZpdC4ycHAucDMuNS45NVtbaV1dWzNdCiAgSW4gPC0gaW4uZml0LjJwcC5wMy41Ljk1W1tpXV0KICByZXR1cm4odHJhbnNpdFRpbWUoQSA9IC0xICogZGlhZyhrcyksIHUgPSBjKEluICogZ2FtLCBJbiAqICgxIC0gZ2FtKSkpKQp9KQpuYW1lcyhUVC4ycHAucDMuNS45NS5scykgPC0gbmFtZXMocGFycy5maXQuMnBwLnAzLjUuOTUpCiMgMnBzClRULjJwcy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHNbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwc1tbaV1dWzNdCiAgSW4gPC0gaW4uZml0LjJwc1tbaV1dCiAgcmV0dXJuKHRyYW5zaXRUaW1lKEEgPSAtMSAqIGRpYWcoa3MpLCB1ID0gYyhJbiAqIGdhbSwgSW4gKiAoMSAtIGdhbSkpKSkKfSkKbmFtZXMoVFQuMnBzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMpCmBgYAoKYGBge3IgU0EtVFQtY29tcH0KIyBjb21wYXJlIGFnZXMgYW5kIHRyYW5zaXQgdGltZXMgYW1vbmcgdGhlIHR3byBtb2RlbCBzdHJ1Y3R1cmVzClNBLjJwLmxzIDwtIGxpc3QoU0EuMnBwLmxzLCBTQS4ycHMubHMsIFNBLjJwcC5wMy41Ljk1LmxzKQpTQS5kZiA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KFNBLjJwLmxzLCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KHNlcV9hbG9uZyhscyksIGZ1bmN0aW9uKGkpIHsKICAgICAgZGF0YS5mcmFtZShhZ2UgPSBjKGxzW1tpXV1bWyJtZWFuU3lzdGVtQWdlIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgbHNbW2ldXVtbIm1lYW5Qb29sQWdlIl1dKSwKICAgICAgICAgICAgICAgICBjb21wb25lbnQgPSBjKCJzeXN0ZW0iLCAiZmFzdCBwb29sIiwgInNsb3cgcG9vbCIpKQogICAgfSkKICB9KQopClNBLmRmJFBNZWNvX2RlcHRoIDwtIHJlcChuYW1lcyhTQS4ycHAubHMpLCBlYWNoID0gMywgdGltZXMgPSBsZW5ndGgoU0EuMnAubHMpKQpTQS5kZiRNb2RlbCA8LSByZXAoYygiMnBwIiwgIjJwcyIsICIycHAgWy41LCAuOTVdIiksIGVhY2ggPSAyNykKVFQuMnAubHMgPC0gbGlzdChUVC4ycHAubHMsIFRULjJwcy5scywgVFQuMnBwLnAzLjUuOTUubHMpClRULmRmIDwtIGJpbmRfcm93cygKICBsYXBwbHkoVFQuMnAubHMsIGZ1bmN0aW9uKGxzKSB7CiAgICBsYXBwbHkoc2VxX2Fsb25nKGxzKSwgZnVuY3Rpb24oaSkgewogICAgIGRhdGEuZnJhbWUoYWdlID0gbHNbW2ldXVtbIm1lYW5UcmFuc2l0VGltZSJdXSwKICAgICAgICAgICAgICAgIGNvbXBvbmVudCA9ICJ0cmFuc2l0IikKICAgIH0pCiAgfSkKKQpUVC5kZiRQTWVjb19kZXB0aCA8LSByZXAobmFtZXMoVFQuMnBwLmxzKSwgdGltZXMgPSBsZW5ndGgoVFQuMnAubHMpKQpUVC5kZiRNb2RlbCA8LSByZXAoYygiMnBwIiwgIjJwcyIsICIycHAgWy41LCAuOTVdIiksIGVhY2ggPSA5KQpTQS5UVC5kZiA8LSByYmluZChTQS5kZiwgVFQuZGYpClNBLlRULmRmJFBNIDwtIHN1YnN0cihTQS5UVC5kZiRQTWVjb19kZXB0aCwgc3RhcnQgPSAxLCBzdG9wID0gMikKU0EuVFQuZGYkZWNvIDwtIHN1YnN0cihTQS5UVC5kZiRQTWVjb19kZXB0aCwgc3RhcnQgPSAzLCBzdG9wID0gNCkKCiMjIFBsb3QgYWdlcyBhbmQgdHJhbnNpdCB0aW1lcwojIGJ5IFBNClNBLlRULmRmICU+JQogIHNlbGVjdCghYyhQTWVjb19kZXB0aCwgZWNvKSkgJT4lCiAgZ3JvdXBfYnkoY29tcG9uZW50LCBQTSwgTW9kZWwpICU+JQogIHN1bW1hcml6ZV9hbGwobGlzdChtZWFuX2FnZSA9IG1lYW4sIHNkID0gc2QpKSAlPiUKICBtdXRhdGUoZXJyX3UgPSBtZWFuX2FnZSArIHNkLAogICAgICAgICBlcnJfbCA9IG1lYW5fYWdlIC0gc2QpICU+JQogIGdncGxvdCguLCBhZXMoTW9kZWwsIG1lYW5fYWdlLCBmaWxsID0gUE0pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgIyBnZW9tX2Vycm9yYmFyKAogICMgICBhZXMoeW1heCA9IGVycl91LCB5bWluID0gZXJyX2wpLCAKICAjICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwKICAjICAgd2lkdGggPSAuMykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIiksCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiQU4iID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICBmYWNldF93cmFwKC4gfiBjb21wb25lbnQsIHNjYWxlcyA9ICJmcmVlIikgKwogIHlsYWIoIm1lYW4gYWdlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgYnkgZWNvClNBLlRULmRmICU+JQogIHNlbGVjdCghYyhQTWVjb19kZXB0aCwgUE0pKSAlPiUKICBncm91cF9ieShjb21wb25lbnQsIGVjbywgTW9kZWwpICU+JQogIHN1bW1hcml6ZV9hbGwobGlzdChtZWFuX2FnZSA9IG1lYW4sIHNkID0gc2QpKSAlPiUKICBtdXRhdGUoZXJyX3UgPSBtZWFuX2FnZSArIHNkLAogICAgICAgICBlcnJfbCA9IG1lYW5fYWdlIC0gc2QpICU+JQogIGdncGxvdCguLCBhZXMoTW9kZWwsIG1lYW5fYWdlLCBmaWxsID0gZWNvKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogICMgZ2VvbV9lcnJvcmJhcigKICAjICAgYWVzKHltYXggPSBlcnJfdSwgeW1pbiA9IGVycl9sKSwKICAjICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwKICAjICAgd2lkdGggPSAuMykgKwogIGZhY2V0X3dyYXAoLiB+IGNvbXBvbmVudCwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYigibWVhbiBhZ2UiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMgQmF5ZXNpYW4gcGFyYW1ldGVyIGVzdGltYXRpb24gKE1DTUMpCgpgYGB7ciBNQ01DLWZpdHMsIGV2YWwgPSBGQUxTRX0KIyB0aGUgZm9sbG93aW5nIC5SRGF0YSBmaWxlcyBhcmUgZ2VuZXJhdGVkIGJ5IHNjcmlwdCAic3JhLXRzL3NvdXJjZS9zcmEtdHMtbWNtYy1iYXllcy5SIgpsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL2JheWVzLXBhci1maXQtMjAyMC0xMS0wNi9iYXllc19maXRfMnBwXzAtMTBfNTAwMGl0ZXIuUkRhdGEiKQpsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL2JheWVzLXBhci1maXQtMjAyMC0xMS0xNy9iYXllc19maXRfMnBzXzAtMTBfNTAwMGl0ZXIuUkRhdGEiKQoKIyAjIHBsb3QgcGFyYW1ldGVyIGNvbnZlcmdlbmNlCiMgbGFwcGx5KGJheWVzX2ZpdF8ycHBfMF8xMCwgcGxvdCkKIyBsYXBwbHkoYmF5ZXNfZml0XzJwc18wXzEwLCBwbG90KQoKIyBwbG90IGNvbGxpbmVhcml0eQppdGVyIDwtIDUwMDAKbGFwcGx5KGJheWVzX2ZpdF8ycHBfMF8xMCwgcGFpcnMsIG5zYW1wbGUgPSBmbG9vcihpdGVyLzQpKQpsYXBwbHkoYmF5ZXNfZml0XzJwc18wXzEwLCBwYWlycywgbnNhbXBsZSA9IGZsb29yKGl0ZXIvNCkpCgojIyBsb29rIGF0IG1vZGVsIHBlcmZvcm1hbmNlCnBhcnMuYmF5ZXMuZGYuZnggPC0gZnVuY3Rpb24obW9kLCBwYXJzLmJheWVzLCBwYXJzLmZpdCkgewogIGJpbmRfcm93cyhsYXBwbHkoc2VxX2Fsb25nKHBhcnMuYmF5ZXMpLCBmdW5jdGlvbihpKSB7CiAgICBpeCA8LSBtYXRjaCh1bmlxdWUocGFycy5iYXllc1tbaV1dW1sicGFycyJdXVssIDFdKSwgcGFycy5iYXllc1tbaV1dW1sicGFycyJdXVssIDFdKQogICAgZGYgPC0gZGF0YS5mcmFtZShrMSA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDFdLAogICAgICAgICAgICAgICAgICAgICBrMiA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDJdLAogICAgICAgICAgICAgICAgICAgICBwMyA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDNdKQogICAgZGYgPC0gY2JpbmQoZGYsCiAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IHJlcChuYW1lcyhwYXJzLmZpdClbaV0sIGxlbmd0aChpeCkpLAogICAgICAgICAgICAgICAgbW9kID0gcmVwKG1vZCwgbGVuZ3RoKGl4KSkpCiAgICBkZiA8LSBjYmluZChkZiwgCiAgICAgICAgICAgICAgICBQTSA9IGZhY3RvcihzdWJzdHIoZGYkUE1lY29fZGVwdGgsIDEsIDIpKSwKICAgICAgICAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoZGYkUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkKICAgIHJldHVybihkZikKICB9KSkKfQpwYXJzLmJheWVzLjJwcC5kZiA8LSBwYXJzLmJheWVzLmRmLmZ4KCIycHAiLCBiYXllc19maXRfMnBwXzBfMTAsIHBhcnMuZml0LjJwcCkKcGFycy5iYXllcy4ycHMuZGYgPC0gcGFycy5iYXllcy5kZi5meCgiMnBzIiwgYmF5ZXNfZml0XzJwc18wXzEwLCBwYXJzLmZpdC4ycHMpCgojICMgbGluZWFyIGZpdHMKIyBzdW1tYXJ5KGxtKGsyIH4gUE0sIHBhcnMuYmF5ZXMuMnBwLmRmKSkKIyBzdW1tYXJ5KGxtKGsyIH4gZWNvLCBwYXJzLmJheWVzLjJwcC5kZikpCiMgc3VtbWFyeShsbShrMSB+IFBNLCBwYXJzLmJheWVzLjJwcC5kZikpCiMgc3VtbWFyeShsbShrMSB+IGVjbywgcGFycy5iYXllcy4ycHAuZGYpKQojIHN1bW1hcnkobG0ocDMgfiBQTSwgcGFycy5iYXllcy4ycHAuZGYpKQojIHN1bW1hcnkobG0ocDMgfiBlY28sIHBhcnMuYmF5ZXMuMnBwLmRmKSkKCiMgYmVzdCBwYXIgc2V0CmJlc3RQYXJzLmJheWVzLmxzIDwtIGxhcHBseShiYXllc19maXRfMnBwXzBfMTAsIGZ1bmN0aW9uKHgpIHsKICByb3VuZChkYXRhLmZyYW1lKGsxID0geCRiZXN0cGFyWzFdLAogICAgICAgICAgICAgICAgICAgazIgPSB4JGJlc3RwYXJbMl0sCiAgICAgICAgICAgICAgICAgICBnYW0gPSB4JGJlc3RwYXJbM10pLAogICAgICAgIDQpCn0pCmJlc3RQYXJzLmJheWVzLmRmIDwtIGNiaW5kKFBNID0gcmVwKGMoIkFOIiwgIkJTIiwgIkdSIiksIGVhY2ggPSAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNvID0gcmVwKGMoInBwIiwgInJmIiwgIndmIiksIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkZXB0aCA9IHJlcCgiMC0xMCIsIDkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoYmVzdFBhcnMuYmF5ZXMubHMpKQoKIyBzdW1tYXJpemUgYnkgUE0KcGFycy5iYXllcy5QTSA8LSBiZXN0UGFycy5iYXllcy5kZiAlPiUKICBzZWxlY3QoIWMoZWNvLCBkZXB0aCkpICU+JQogIGdyb3VwX2J5KFBNKSAlPiUKICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSAlPiUKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZm9ybWF0LCBkaWdpdHMgPSAzKQojIHN1bW1hcml6ZSBieSBFQ08KcGFycy5iYXllcy5lY28gPC0gYmVzdFBhcnMuYmF5ZXMuZGYgJT4lCiAgc2VsZWN0KCFjKFBNLCBkZXB0aCkpICU+JQogIGdyb3VwX2J5KGVjbykgJT4lCiAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkgJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZvcm1hdCwgZGlnaXRzID0gMykKCiMgcGxvdCBiZXN0IHBhcnMKYmVzdFBhcnMuYmF5ZXMuZGYgJT4lCiAgcGl2b3RfbG9uZ2VyKCEoUE06ZGVwdGgpLCBuYW1lc190byA9ICJwYXIiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUoUE0gPSBmYWN0b3IoUE0pLAogICAgICAgICBlY28gPSBmYWN0b3IoZWNvLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwYXIsIHZhbHVlLCBjb2xvciA9IFBNLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX2ppdHRlcihzaXplID0gNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gcGFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBwbG90IGFjY2VwdGVkIHBhcnMgYnkgUE0gYW5kIHRoZW4gYnkgZWNvCnBhcnMuYmF5ZXMuZGYgJT4lCiAgcGl2b3RfbG9uZ2VyKCFjKFBNLCBlY28sIFBNZWNvX2RlcHRoKSwgbmFtZXNfdG8gPSAicGFyIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgbXV0YXRlKFBNID0gZmFjdG9yKFBNKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGVjbywgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogIGdncGxvdCguLCBhZXMocGFyLCB2YWx1ZSwgZmlsbCA9IFBNKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gcGFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpwYXJzLmJheWVzLmRmICU+JQogIHBpdm90X2xvbmdlcighYyhQTSwgZWNvLCBQTWVjb19kZXB0aCksIG5hbWVzX3RvID0gInBhciIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIG11dGF0ZShQTSA9IGZhY3RvcihQTSksCiAgICAgICAgIGVjbyA9IGZhY3RvcihlY28sIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBhciwgdmFsdWUsIGZpbGwgPSBlY28pKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAoLiB+IHBhciwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBg